MySql EF Core Provider中Linq查询Contains用法失败求助
解决方案
问题原因
Pomelo.EntityFrameworkCore.MySql 8.0.2 默认未启用原始集合支持,导致无法翻译内存集合的 Any(y => y.Contains(x.ExternalNumber.ToUpper())) 这类组合查询逻辑。
方案一:启用原始集合支持
直接在 DbContext 配置中开启该特性,原查询即可正常运行:
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseMySql( "你的MySQL连接字符串", new MySqlServerVersion(new Version(8, 0, 21)), // 匹配你的MySQL服务版本 options => options.EnablePrimitiveCollections() // 开启原始集合翻译支持 ); }
注:该特性在 Pomelo 5.0.0 及以上版本可用,你的 8.0.2 版本完全兼容。
方案二:手动构建OR条件组合查询
如果不想启用原始集合支持,可将内存集合的每个元素转换成独立的过滤条件,再用OR逻辑拼接:
方式1:使用LinqKit简化表达式拼接
先通过 NuGet 安装 LinqKit.Microsoft.EntityFrameworkCore,再重构查询:
// 先处理内存集合,转成List避免多次枚举 var upperStringList = listStringValues.Where(x => x != null).Select(x => x.ToUpper()).ToList(); // 构建外部编号的过滤条件 var externalNumberPredicate = PredicateBuilder.False<Invoice>(); foreach (var value in upperStringList) { var currentValue = value; // 捕获循环变量,避免闭包引用问题 externalNumberPredicate = externalNumberPredicate.Or(x => currentValue.Contains(x.ExternalNumber.ToUpper())); } // 组合最终查询 var query = _ctx.Invoices .Where(x => (x.FormatType.FormatTypeCode == FormatTypeCode.ER || x.FormatType.FormatTypeCode == FormatTypeCode.AR || x.FormatType.FormatTypeCode == FormatTypeCode.EA || x.FormatType.FormatTypeCode == FormatTypeCode.AA) && externalNumberPredicate.Invoke(x)) .AsExpandable(); // LinqKit需要调用此方法解析表达式
方式2:手动拼接表达式树(无需第三方库)
using System.Linq.Expressions; // 处理内存集合 var upperStringList = listStringValues.Where(x => x != null).Select(x => x.ToUpper()).ToList(); // 初始化条件为false Expression<Func<Invoice, bool>> externalNumberCondition = x => false; foreach (var value in upperStringList) { var currentValue = value; // 构建单个条件:currentValue.Contains(x.ExternalNumber.ToUpper()) var parameter = Expression.Parameter(typeof(Invoice), "x"); var externalNumberUpper = Expression.Call( Expression.Property(parameter, nameof(Invoice.ExternalNumber)), typeof(string).GetMethod(nameof(string.ToUpper), Type.EmptyTypes)!); var containsCall = Expression.Call( Expression.Constant(currentValue), typeof(string).GetMethod(nameof(string.Contains), new[] { typeof(string)})!, externalNumberUpper); var singleCondition = Expression.Lambda<Func<Invoice, bool>>(containsCall, parameter); // 合并到总条件(OR逻辑) externalNumberCondition = Expression.Lambda<Func<Invoice, bool>>( Expression.OrElse(externalNumberCondition.Body, Expression.Invoke(singleCondition, externalNumberCondition.Parameters)), externalNumberCondition.Parameters); } // 组合查询 var query = _ctx.Invoices .Where(x => (x.FormatType.FormatTypeCode == FormatTypeCode.ER || x.FormatType.FormatTypeCode == FormatTypeCode.AR || x.FormatType.FormatTypeCode == FormatTypeCode.EA || x.FormatType.FormatTypeCode == FormatTypeCode.AA) && externalNumberCondition.Invoke(x)) .AsExpandable();
可选优化:用EF.Functions.Like生成标准SQL
如果希望生成更贴近原生SQL的LIKE语句,可替换Contains为EF.Functions.Like:
var externalNumberPredicate = PredicateBuilder.False<Invoice>(); foreach (var value in upperStringList) { var currentValue = value; externalNumberPredicate = externalNumberPredicate.Or(x => EF.Functions.Like(x.ExternalNumber.ToUpper(), $"%{currentValue}%")); }
内容的提问来源于stack exchange,提问作者SB_84
相关产品推荐
相关产品推荐

