首页 > 解决方案 > 使用实体框架客户端与服务器评估更改

问题描述

我的查询有以下例外情况。我正在使用带有 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()

亚瑟

标签: entity-framework-coreef-core-3.1

解决方案


因此,如下所示,我已更改(根据我阅读的内容)以在每个部分中使用 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) 进行所需的格式化。stringTitleText SelectWhere

无论如何,我不能确切地告诉你,因为你没有展示你的模型,但删除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并设置执行此操作的值转换器。


推荐阅读