entity-framework-core - 使用实体框架客户端与服务器评估更改
问题描述
我的查询有以下例外情况。我正在使用带有 EF Core 的 ASP.NET Core 3.1 项目。
我读到服务器与客户端发生了变化,所以我过去在 Core 2.1 中执行 WHERE 部分的方式(使用代码中其他地方的变量)似乎不再起作用。
因此,如下所示,我已更改(根据我阅读的内容)在每个部分中使用 ToList(),但现在它不会更多地访问数据库(在我的 Core 2.1 中,我只会在最后部分使用 ToList下面的代码注释)。
所以现在对于Core 3.1,我需要在初始“//加载数据”部分有一个动态的位置-我如何在初始部分做一个动态的位置,或者有没有办法,现在服务器与客户端的变化在EF中解决该问题的核心(请注意,它是在 Core 3.1 下的 EF 中失败的最终“// 搜索”部分(在添加 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()
亚瑟
解决方案
因此,如下所示,我已更改(根据我阅读的内容)以在每个部分中使用 ToList()
EF Core 3.x+ 客户端评估异常消息建议( 1)
以可翻译的形式重写查询
或(2)
通过插入对 AsEnumerable()、AsAsyncEnumerable()、ToList() 或 ToListAsync() 的调用,显式切换到客户端评估
因此,您选择了更容易的选项 (2),但您应该尝试使用更难但从性能角度来看更好的选项 (1),这是 EFC 3.0 删除了隐式客户端评估的主要原因。只有在无法应用选项 (1) 的情况下,选项 (2) 才应该是您的最后手段。
异常消息还包含失败的表达式。不幸的是,它不是确切的部分,而是整个表达式(Where
例如整个谓词),因此您需要对其进行分析,找到失败的部分并尝试用可翻译的结构替换它们。
简单数据表达式的一般规则之一是避免显式转换 ( ToString()
, Parse
)。在数据库中存储日期和数字而不是字符串,或者在使用旧的现有数据库时使用值转换并且不允许更改它。
在这个特定查询中,不受支持(不可翻译)的构造很可能是类型属性的ToString()
调用(例如, )。EF Core 仍然支持对final的隐式客户端评估,因此如果在引用此类表达式之后没有(或其他)子句,您将不会注意到它。但正如一开始所说,无论如何你都应该避免使用它们——查询原始数据并让使用 (UI) 进行所需的格式化。string
Title
Text
Select
Where
无论如何,我不能确切地告诉你,因为你没有展示你的模型,但删除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
,所以通过字符串进行双重转换没有意义,并且会引起类似的麻烦。即使数据库类型是字符串,仍然删除Parse
/ToString
并设置执行此操作的值转换器。
推荐阅读
- java-8 - 如何通过避免手动睡眠来对 CompletableFuture.thenAccept() 进行单元测试
- python - 会话夹具不被调用和全局变量共享
- c# - 为什么我的贴花投影仪同时撞击墙壁和地板时生成错误?
- excel - 查找行中的最后一个条目,然后返回该列顶行中单元格的值
- scala - 如何使用 Spark 2.2 使用 TestHiveContext
- python - SelectField“不是一个有效的选择”
- angular - 如何自定义离子输入占位符
- tfs - 如何设置 TFS 2018 看板以仅显示叶子工作项(用户故事)
- c# - CloudBlobContainer.ListBlobs() 中如何使用前缀参数从 Azure Blob 存储中的虚拟文件夹获取文件
- java - 使用改造时我的注册有问题