【问题标题】:Query with `groupjoin` cannot be translated although it's documened as being supported使用 `groupjoin` 的查询无法翻译,尽管它被记录为受支持
【发布时间】: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 的原因。

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

【问题讨论】:

    标签: entity-framework-core


    【解决方案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; }
      }
      

      见:

      【讨论】:

      • 很遗憾,我不能使用导航属性。让我尝试不使用ToList()。编辑:删除 ToList() 并不能解决问题。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-13
      • 1970-01-01
      • 2020-10-21
      • 1970-01-01
      • 2021-06-23
      • 2021-09-10
      • 2021-12-08
      相关资源
      最近更新 更多