使用LINQ查询语法执行分组JOIN失败,报错表达式无法翻译
问题描述
执行LINQ查询语法的关联查询时,出现以下错误:
The LINQ expression 'DbSet()
.GroupJoin(
inner: DbSet(),
outerKeySelector: a => (int?)a.ID,
innerKeySelector: b => b.aID,
resultSelector: (a, b) => new {
// my properties here
})' 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'.
原代码大致如下:
var q = from a in As join b in Bs on a.ID equals b.aID into bs select new { // 自定义属性 };
需求是关联Bs表,并在返回的属性中对bs集合执行Count()操作。
解决方法
方法1:使用实体导航属性(推荐)
如果实体类中已定义导航关系(比如A类包含ICollection<B> Bs属性),直接通过导航属性访问关联数据,EF可正确翻译为SQL:
var q = from a in As select new { AId = a.ID, BCount = a.Bs.Count(), // 其他需要的属性 };
方法2:改用子查询替代GroupJoin
显式GroupJoin有时会出现翻译问题,换成子查询形式可避免该问题,EF能直接生成对应的SQL子查询:
var q = from a in As select new { AId = a.ID, BCount = Bs.Count(b => b.aID == a.ID), // 其他需要的属性 };
方法3:确保关联键类型匹配
错误提示中出现(int?)a.ID,说明关联键的可空性不匹配。若b.aID是可空类型,需将a.ID转换为对应可空类型后再关联:
var q = from a in As join b in Bs on (int?)a.ID equals b.aID into bs select new { AId = a.ID, BCount = bs.Count(), // 其他需要的属性 };
注:此方法仍可能存在翻译问题,优先使用前两种方案。
说明
以上方法均可避免客户端评估(客户端评估会将全量数据拉取到本地计算,性能较差),在LINQPad中测试可正常生成对应的SQL语句。
内容的提问来源于stack exchange,提问作者user746019

