MySQL EF Core 9数组Contains查询无法转SQL问题求助
问题场景
在MySQL数据库中执行LINQ的Contains查询时无法转换为对应的SQL语句,但相同代码在SQL Server中可正常运行。
代码示例
var arr = new long[] { 5, 3, 2 }; var results = await _datacontext.ChatMessages .Where(x => arr.Contains(x.ChatMessageId)) .ToListAsync(cancellationToken)
ChatMessage实体定义
public class ChatMessage { public long ChatMessageId { get;set; } }
错误信息
System.InvalidOperationException: 'The LINQ expression '@__arr_0' could not be translated. Additional information: Primitive collections support has not been enabled. Either rewrite the query in a form that can be translated, or switch to client evaluation explicitly by inserting a call to 'AsEnumerable', 'AsAsyncEnumerable', 'ToList', or 'ToListAsync'.
问题原因
该查询在MySQL中无法正常工作,核心原因是所用的EF Core MySQL驱动(如Pomelo.EntityFrameworkCore.MySql)默认未启用原始集合支持,而SQL Server的EF Core驱动原生支持将Contains语法转换为IN语句。
解决办法
启用原始集合支持(推荐)
如果使用Pomelo EF Core驱动,可在DbContext的OnConfiguring方法中开启该特性,之后Contains会自动转换为MySQL的IN语句:protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) { optionsBuilder.UseMySql("你的MySQL连接字符串", ServerVersion.AutoDetect("你的MySQL连接字符串")) .EnablePrimitiveCollectionsSupport(); }手动构造参数化IN查询
若不想启用特性,可通过原生SQL实现参数化的IN查询,避免SQL注入:var arr = new long[] { 5, 3, 2 }; var parameters = arr.Select((val, idx) => new MySqlParameter($"@p{idx}", val)).ToArray(); var inClause = string.Join(",", parameters.Select(p => p.ParameterName)); var results = await _datacontext.ChatMessages .FromSqlRaw($"SELECT * FROM ChatMessages WHERE ChatMessageId IN ({inClause})", parameters) .ToListAsync(cancellationToken);客户端评估(不推荐)
若数据集极小,可先将全表数据加载到内存再过滤,但此方式性能损耗大:var results = await _datacontext.ChatMessages .AsEnumerable() .Where(x => arr.Contains(x.ChatMessageId)) .ToListAsync(cancellationToken);
内容的提问来源于stack exchange,提问作者Tyrone

