EF Core 5中带StringComparison的string.Equals LINQ查询无法翻译报错如何处理
问题根因
EF Core 3.0及以上版本调整了查询翻译规则:
- 禁止无法翻译的LINQ查询隐式执行客户端评估
- 带
StringComparison参数的string.Equals重载暂不支持翻译为SQL语句
你之前EF Core 2.2版本能正常运行,是因为2.2会自动把无法翻译的部分放到客户端执行,升级到5.0后不符合规则就直接抛出异常。
解决方案
方案1:数据库端执行(推荐,性能更优)
优先把逻辑翻译为SQL在数据库层执行,避免加载大量数据到内存。
写法1:使用可翻译的字符串比较重载
直接去掉StringComparison参数,无参的string.Equals可正常翻译为SQL的等于判断:
public async Task<bool> DoesItemNumberExists(Guid revisionId, string itemNumber) { var doesExist = await _repository.AnyAsync(a => a.ItemNo.Equals(itemNumber) && a.SoqHeading_NP.SoqRevisionId == revisionId); return doesExist; }
写法2:显式指定排序规则(适配大小写敏感需求)
如果数据库默认排序规则是大小写不敏感,需要和StringComparison.Ordinal保持一致的大小写敏感匹配,可以通过EF.Functions.Collate指定对应排序规则:
public async Task<bool> DoesItemNumberExists(Guid revisionId, string itemNumber) { // 不同数据库的排序规则写法有差异,示例为SQL Server的大小写敏感排序规则 var doesExist = await _repository.AnyAsync(a => EF.Functions.Collate(a.ItemNo, "SQL_Latin1_General_CP1_CS_AS") == itemNumber && a.SoqHeading_NP.SoqRevisionId == revisionId); return doesExist; }
方案2:显式客户端评估(适合小数据量场景)
如果必须要在C#侧使用StringComparison做比较,可以先把符合其他过滤条件的数据加载到内存,再执行字符串比较:
public async Task<bool> DoesItemNumberExists(Guid revisionId, string itemNumber) { // 先执行可翻译的过滤逻辑,缩小加载到内存的数据量 var matchedItems = await _repository .Where(a => a.SoqHeading_NP.SoqRevisionId == revisionId) .ToListAsync(); // 内存中执行Ordinal规则的字符串比较 return matchedItems.Any(a => string.Equals(a.ItemNo, itemNumber, StringComparison.Ordinal)); }
注意:客户端评估需要尽量提前过滤数据,避免加载全量数据到内存导致性能问题。
内容的提问来源于stack exchange,提问作者thanzeel
相关产品推荐
相关产品推荐

