EF Core拼接字段后判断是否在字符串列表中无法翻译如何解决
报错原因是EF Core无法将C#原生的字符串插值、带格式的ToString()方法翻译为SQL语句,可采用以下方案解决:
方案一:拆分过滤条件(推荐,性能最优)
提前将本地字符串列表拆分为三个字段对应的数值,直接做数值匹配,可完全在数据库端执行,还能用到字段索引。
预处理代码:
// 提前把列表中的字符串拆成三个字段对应的数值 var filterTuples = list.Select(str => new { Int1Val = int.Parse(str.Substring(0, 2)), Int2Val = int.Parse(str.Substring(2, 3)), Int3Val = int.Parse(str.Substring(5, 1)) }).ToList();
查询代码(EF Core 5.0及以上版本支持):
myentities = myentities .Where(e => filterTuples.Any(t => t.Int1Val == e.int1 && t.Int2Val == e.int2 && t.Int3Val == e.int3)) .ToList();
该方案会被翻译为多列IN查询,执行效率最高。
方案二:使用EF.Functions做数据库端字符串拼接
如果EF Core版本较低不支持多列匹配,可使用EF内置的函数实现数据库端的补零、拼接操作,避免用C#原生方法:
myentities = myentities .Where(e => list.Contains( EF.Functions.Concat( // 给int1补前导零到2位 EF.Functions.Right(EF.Functions.Concat("00", e.int1), 2), // 给int2补前导零到3位 EF.Functions.Right(EF.Functions.Concat("000", e.int2), 3), e.int3.ToString() ) )) .ToList();
该方案所有逻辑仍在数据库端执行,但需要对每行数据做字符串运算,数据量大时性能弱于方案一。
方案三:内存过滤(仅适合表数据量极小的场景)
如果数据量非常小,可以先把全表数据加载到内存,再用C#原生逻辑过滤:
// 注意:会加载全表数据,仅可用于表数据量不足千条的场景 myentities = myentities .ToList() .Where(e => list.Contains($"{e.int1.ToString("00")}{e.int2.ToString("000")}{e.int3.ToString("0")}")) .ToList();
该方案性能最差,数据量稍大就会出现严重的性能问题,不推荐使用。
内容的提问来源于stack exchange,提问作者SNO
相关产品推荐
相关产品推荐

