使用 `groupjoin` 的查询无法翻译,尽管它被记录为受支持

Posted

技术标签:

【中文标题】使用 `groupjoin` 的查询无法翻译,尽管它被记录为受支持【英文标题】:Query with `groupjoin` cannot be translated although it's documened as being supported 【发布时间】:2021-06-24 21:59:04 【问题描述】:

我不明白为什么这不能翻译。这似乎正是here 描述的用例。

LINQ 表达式

DbSet<A>()
    .GroupJoin(
        inner: DbSet<B>(),
        outerKeySelector: a => a.AId,
        innerKeySelector: b => b.AId,
        resultSelector: (a, bs) => new 
            a = a,
            bs = bs
         )

产生错误:

无法翻译。以可翻译的形式重写查询,或通过插入对“AsEnumerable”、“AsAsyncEnumerable”、“ToList”或“ToListAsync”的调用显式切换到客户端评估。请参阅https://go.microsoft.com/fwlink/?linkid=2101038 了解更多信息。

产生异常的 LINQ 代码是

from a in ctx.As
    join b in ctx.Bs on a.aId equals b.aId into bs
    select new A = a, Bs = bs.ToList();

编辑:也许我误解了文档,这是一个不翻译的例子。

执行类似以下示例的查询会生成 Blog 和 IEnumerable 的结果。由于数据库(尤其是关系数据库)无法表示客户端对象的集合,因此 GroupJoin 在许多情况下不会转换为服务器。它要求您从服务器获取所有数据以在没有特殊选择器的情况下进行 GroupJoin(下面的第一个查询)。但是如果选择器限制了被选择的数据,那么从服务器获取所有数据可能会导致性能问题(下面的第二个查询)。这就是 EF Core 不翻译 GroupJoin 的原因。

但后来我的问题变成了:如何在不需要导航属性的情况下实现我正在寻找的结果?

【问题讨论】:

【参考方案1】:

链接文档中的解释只是遵循 EF Core 团队的愿景并且很荒谬,因为它当然可以很容易地翻译 - 我在这里与团队进行了长时间的讨论 Query with GroupBy or GroupJoin throws exception #17068 并在此处继续 Query: Support GroupJoin when it is final query operator #19930,试图说服他们为什么应该支持它,不管争论如何,都没有运气。

重点是(这是当前的解决方法)它可以像关联子查询 (SelectMany) 一样进行处理,并正确翻译和处理(即使查询结果形状没有 SQL 等效项。

无论如何,当前状态是“需要设计”(无论这意味着什么),解决方法是用相关子查询替换联接(这是 EF Core 在查询翻译期间“扩展”集合导航属性时在内部使用的)。

在你的情况下,替换

join b in ctx.Bs on a.aId equals b.aId into bs

let bs = ctx.Bs.Where(b => a.aId == b.aId)

但是,我强烈建议添加和使用导航属性。不知道为什么你“不能使用”它们,在 LINQ to Entities 中,它们不投射实体,它们只为关系提供元数据,从而自动生成必要的连接。通过不定义它们,您只是给自己施加了不必要的限制(除了 EF Core 限制/错误)。一般来说,当使用导航属性而不是手动连接时,EF Core 会更好地工作并支持更多的东西。

【讨论】:

谢谢,这似乎是我要找的。我不使用导航属性,因为它们至少在我的用例中容易出错。此外,我更喜欢使连接显式并具有更简单的实体类型 s.t.我没有忘记关系数据库管理的局限性【参考方案2】:

试试这个查询,它应该适用于 EF Core:

var query =
    from a in ctx.As
    select new A = a, Bs = ctx.Bs.Where(b => b.Id == a.aId).ToList();

【讨论】:

【参考方案3】:

.ToList() 可能无法翻译。改用包含

var result = ctx.As
    .Include(a => a.Bs)
    .ToList();

你必须为 A 类中的 B 提供导航属性:

public class A

    public int aId  get; set; 
    public List<B> Bs  get; set; 

见:

Eager Loading of Related Data Relationships - EF Core

【讨论】:

很遗憾,我不能使用导航属性。让我尝试不使用ToList()。编辑:删除 ToList() 并不能解决问题。

以上是关于使用 `groupjoin` 的查询无法翻译,尽管它被记录为受支持的主要内容,如果未能解决你的问题,请参考以下文章

GroupJoin with list返回多个结果,而不是按结果附加列表

Linq GroupJoin (join...into) 导致 INNER JOIN?

Linq 语法

EF多表查询方式

LINQ to SQL语句之Join

linq语法大全(转集)