使用 Entity Framework 客户端与服务器评估更改
Working with Entity Framework client vs server evaluation changes
我的查询有以下摘录。我在 EF Core 中使用 ASP.NET Core 3.1 项目。
我读到服务器与客户端发生了变化,所以我以前在 Core 2.1 中执行 WHERE 部分的方式(使用代码中其他地方的变量)似乎不再有效。
因此,如下所示,我已更改(根据我阅读的内容)在每个部分中使用 ToList(),但现在它不会更多地访问数据库(在我的 Core 2.1 中,我只会将 ToList 放在根据下面的代码注释的最后部分)。
所以现在对于 Core 3.1,我需要在初始“//加载数据”部分中有一个动态位置 - 我如何在初始部分中动态位置,或者有什么办法,现在服务器 vs客户端更改在 EF Core 中解决这个问题(请注意,在 Core 3.1 下,EF 中最后的“// Search”部分失败(在添加 ToList 之前)
public List<KBEntryListVM> lstKBEntry;
// Load data
var q = await (from _k in _context.KBEntry
join _kc in _context.KBCategory on _k.CategoryId equals _kc.Id
into _kc2
from _kc3 in _kc2.DefaultIfEmpty()
select new KBEntryListVM()
{
Id = _k.Id,
DateCreated = DateTime.Parse(_k.DateCreated.ToString()),
CategoryId = _k.CategoryId,
CategoryTitle = _kc3.Title.ToString().Trim(),
Text = _k.Text.ToString().Trim(),
Title = _k.Title.ToString().Trim()
}).ToListAsync();
// KBCategory
if (!string.IsNullOrEmpty(c) && Guid.TryParse(c.ToString().Trim(), out var newGuid))
{
q = q.Where(w => w.CategoryId == Guid.Parse($"{c.ToString()}")).ToList();
}
// Search
if (!string.IsNullOrEmpty(s))
{
q = q.Where(w => w.Title.ToLower().Contains($"{s.ToLower()}") || w.CategoryTitle.ToLower().Contains($"{s.ToLower()}") || w.Text.ToLower().Contains($"{s.ToLower()}")).ToList();
}
lstKBEntry = q; //.ToList(); this would of been the only place in Core 2.1 I would of had ToList()
亚瑟
So as below I have changed (as per something I read) to use ToList() in each part
EF Core 3.x+ 客户端评估异常消息建议 (1)
rewrite the query in a form that can be translated
或 (2)
switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync()
所以您选择了更简单的选项 (2),但您应该尝试使用更难的选项 (1),但从性能角度来看更好,这也是隐式客户端评估已被 EFC 3.0 删除的主要原因.只有在无法应用选项 (1) 的情况下,选项 (2) 才应该是你的最后选择。
异常消息还包含失败的表达式。不幸的是,它不是确切的部分,而是整个表达式(例如整个 Where
谓词),因此您需要分析它,找到失败的部分并尝试用可翻译的结构替换它们。
简单数据表达式的一般规则之一是避免显式转换(ToString()
、Parse
)。在数据库中存储日期和数字而不是字符串,或者在使用旧的现有数据库时使用 value conversions 并且不允许更改它。
在此特定查询中,不受支持(不可翻译)的构造很可能是 ToString()
对 string
类型属性(例如 Title
、Text
)的调用。 EF Core 仍然支持 final Select
的隐式客户端评估,因此如果在引用之后没有 Where
(或其他)子句,您将不会注意到它这样的表达。但正如开头所说,无论如何你都应该避免它们 - 查询原始数据并让用法(UI)进行所需的格式化。
无论如何,我不能确切地说,因为你没有显示你的模型,但删除 ToString()
应该使查询可翻译,因此不需要中间 ToList()
或类似的客户端实现:
CategoryTitle = _kc3.Title.Trim(),
Text = _k.Text.Trim(),
Title = _k.Title.Trim()
你或许还应该更换
DateCreated = DateTime.Parse(_k.DateCreated.ToString())
只有
DateCreated = _k.DateCreated
因为好像DateCreated
已经是DateTime
了,所以通过string进行二次转换就没有意义了,会造成类似的麻烦。即使数据库类型是字符串,仍然删除 Parse
/ ToString
和设置值转换器。
我的查询有以下摘录。我在 EF Core 中使用 ASP.NET Core 3.1 项目。
我读到服务器与客户端发生了变化,所以我以前在 Core 2.1 中执行 WHERE 部分的方式(使用代码中其他地方的变量)似乎不再有效。
因此,如下所示,我已更改(根据我阅读的内容)在每个部分中使用 ToList(),但现在它不会更多地访问数据库(在我的 Core 2.1 中,我只会将 ToList 放在根据下面的代码注释的最后部分)。
所以现在对于 Core 3.1,我需要在初始“//加载数据”部分中有一个动态位置 - 我如何在初始部分中动态位置,或者有什么办法,现在服务器 vs客户端更改在 EF Core 中解决这个问题(请注意,在 Core 3.1 下,EF 中最后的“// Search”部分失败(在添加 ToList 之前)
public List<KBEntryListVM> lstKBEntry;
// Load data
var q = await (from _k in _context.KBEntry
join _kc in _context.KBCategory on _k.CategoryId equals _kc.Id
into _kc2
from _kc3 in _kc2.DefaultIfEmpty()
select new KBEntryListVM()
{
Id = _k.Id,
DateCreated = DateTime.Parse(_k.DateCreated.ToString()),
CategoryId = _k.CategoryId,
CategoryTitle = _kc3.Title.ToString().Trim(),
Text = _k.Text.ToString().Trim(),
Title = _k.Title.ToString().Trim()
}).ToListAsync();
// KBCategory
if (!string.IsNullOrEmpty(c) && Guid.TryParse(c.ToString().Trim(), out var newGuid))
{
q = q.Where(w => w.CategoryId == Guid.Parse($"{c.ToString()}")).ToList();
}
// Search
if (!string.IsNullOrEmpty(s))
{
q = q.Where(w => w.Title.ToLower().Contains($"{s.ToLower()}") || w.CategoryTitle.ToLower().Contains($"{s.ToLower()}") || w.Text.ToLower().Contains($"{s.ToLower()}")).ToList();
}
lstKBEntry = q; //.ToList(); this would of been the only place in Core 2.1 I would of had ToList()
亚瑟
So as below I have changed (as per something I read) to use ToList() in each part
EF Core 3.x+ 客户端评估异常消息建议 (1)
rewrite the query in a form that can be translated
或 (2)
switch to client evaluation explicitly by inserting a call to either AsEnumerable(), AsAsyncEnumerable(), ToList(), or ToListAsync()
所以您选择了更简单的选项 (2),但您应该尝试使用更难的选项 (1),但从性能角度来看更好,这也是隐式客户端评估已被 EFC 3.0 删除的主要原因.只有在无法应用选项 (1) 的情况下,选项 (2) 才应该是你的最后选择。
异常消息还包含失败的表达式。不幸的是,它不是确切的部分,而是整个表达式(例如整个 Where
谓词),因此您需要分析它,找到失败的部分并尝试用可翻译的结构替换它们。
简单数据表达式的一般规则之一是避免显式转换(ToString()
、Parse
)。在数据库中存储日期和数字而不是字符串,或者在使用旧的现有数据库时使用 value conversions 并且不允许更改它。
在此特定查询中,不受支持(不可翻译)的构造很可能是 ToString()
对 string
类型属性(例如 Title
、Text
)的调用。 EF Core 仍然支持 final Select
的隐式客户端评估,因此如果在引用之后没有 Where
(或其他)子句,您将不会注意到它这样的表达。但正如开头所说,无论如何你都应该避免它们 - 查询原始数据并让用法(UI)进行所需的格式化。
无论如何,我不能确切地说,因为你没有显示你的模型,但删除 ToString()
应该使查询可翻译,因此不需要中间 ToList()
或类似的客户端实现:
CategoryTitle = _kc3.Title.Trim(),
Text = _k.Text.Trim(),
Title = _k.Title.Trim()
你或许还应该更换
DateCreated = DateTime.Parse(_k.DateCreated.ToString())
只有
DateCreated = _k.DateCreated
因为好像DateCreated
已经是DateTime
了,所以通过string进行二次转换就没有意义了,会造成类似的麻烦。即使数据库类型是字符串,仍然删除 Parse
/ ToString
和设置值转换器。