IEnumerable与IQueryable能否执行Union操作?
尝试对IQueryable和IEnumerable执行Union操作时,遇到如下错误:
'Union(__p_2)' could not be translated. 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'.
想咨询:IEnumerable和IQueryable能否进行Union操作?
相关代码如下:
var users = new List<Person>().AsQueryable(); var user = GetUsersByXXX(XXX, YYY); // return IQueryable<Person> var userExtra = GetUsersExtraByXXX(XXX, YYY); // return IEnumerable<Person> if (userExtra.Any()) { users = user.Union(userExtra); } return await users.AsNoTracking().OrderBy(x => x.NAME ).ToListAsync();
实体类定义:
public class Person { public string CODE { get; set; } public string NAME { get; set; } public string PHONE { get; set; } }
IQueryable和IEnumerable可以执行Union,但要注意EF Core的查询翻译限制——它无法将内存中的IEnumerable集合直接翻译成数据库SQL语句,因此会抛出你遇到的错误。针对不同场景,有两种解决方法:
场景1:优先数据库端合并(推荐,性能更优)
如果GetUsersExtraByXXX可以改为返回IQueryable<Person>,直接对两个IQueryable执行Union,EF Core能正常将逻辑翻译成SQL,在数据库端完成合并操作,避免内存加载大量数据:// 修改GetUsersExtraByXXX返回IQueryable<Person> var userExtra = GetUsersExtraByXXX(XXX, YYY); // return IQueryable<Person> if (userExtra.Any()) { users = user.Union(userExtra); }场景2:必须在内存中合并
如果userExtra只能是IEnumerable类型,需要先将数据库端的IQueryable拉取到内存(转为IEnumerable),再执行Union:if (userExtra.Any()) { // 先将IQueryable转为内存集合,再与userExtra合并 users = user.AsEnumerable().Union(userExtra).AsQueryable(); }注意:这种方式会先加载
user的所有数据到内存,数据量大时可能影响性能,需谨慎使用。
另外,代码中初始的users = new List<Person>().AsQueryable();可以优化,直接将user作为默认值:
var users = user; if (userExtra.Any()) { users = user.AsEnumerable().Union(userExtra).AsQueryable(); }
内容的提问来源于stack exchange,提问作者Puthxii

