在Linq中使用包含与相交/联合/排除

时间:2018-11-09 23:22:43

标签: c# linq entity-framework-core entity-framework-core-2.1

似乎应该是一个相对简单的任务已经变成了一个令人惊讶的复杂问题。到现在,我开始认为我的方法论可能超出了Linq的功能范围。

我想做的是将一个Linq查询拼在一起,然后调用.Include()以便从多个子实体中提取值。例如,假设我有以下实体:

public class Parent
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Location { get; set; }
    public ISet<Child> Children { get; set; }
}

public class Child
{
    public int Id { get; set; }
    public int ParentId { get; set; }
    public Parent Parent { get; set; }
    public string Name { get; set; }
}

假设我要执行一个查询以从Parent中检索记录,其中Name是某个值,而Location是某个其他值,然后包含Child记录。但是无论出于什么原因,我都不同时知道NameLocation的查询值,因此我必须采用两个单独的查询并将其联接,例如:

MyDbContext C = new MyDbContext();
var queryOne = C.Parent.Where(p => p.Name == myName);
var queryTwo = C.Parent.Where(p => p.Location == myLocation);
var finalQuery = queryOne.Intersect(queryTwo);

那很好,可以像我刚做的一样产生结果:

var query = C.Parent.Where(p => p.Name == myName && p.Location = myLocation);

同样,我可以:

var finalQuery = queryOne.Union(queryTwo);

要给我像我一样的结果:

var query = C.Parent.Where(p => p.Name == myName || p.Location = myLocation);

但是,一旦应用了Intersect()Union()之后,我便无法使用Child映射Include(),如下所示:< / p>

finalQuery.Include(p => p.Children);

该代码将编译,但产生的结果如下:

  1. 对于Union(),将生成结果集,但不会枚举Child实体。
  2. 对于Intersect(),尝试应用Include()时会生成运行时错误,如下所示:
  

类型的表达   'System.Collections.Generic.IEnumerable`1 [Microsoft.EntityFrameworkCore.Query.Internal.AnonymousObject]'   不能用于类型的参数   方法的“ System.Collections.Generic.IEnumerable`1 [System.Object]”   'System.Collections.Generic.IEnumerable`1 [System.Object]   Intersect [Object](System.Collections.Generic.IEnumerable`1 [System.Object],   System.Collections.Generic.IEnumerable`1 [System.Object])'

让我感到困惑的是,该代码将完全按预期工作:

var query = C.Parent.Where(p => p.Name == myName).Where(p => p.Location == myLocation);
query.Include(p => p.Children);

即具有所需的结果,包括枚举的Child实体。

1 个答案:

答案 0 :(得分:3)

  

我的方法论可能与Linq的功能完全不在范围内

问题不是LINQ,而是EF Core查询翻译,尤其是缺少Intersect / Union / Concat / Except方法SQL翻译,{ {3}}。

很快,此类查询当前使用#6812 Query: Translate IQueryable.Concat/Union/Intersect/Except/etc. to server,结合EF Core处理Include的方式会导致许多意外的运行时异常(如您的案例2)或错误的行为(如{{3 }}(在您的案例1中)。

因此,根据EF Core团队负责人的回答,虽然从技术上来说您的方法非常合理

  

将其更改为在服务器上生成单个SQL查询目前不是最高优先级

因此,尽管计划更改(重写)整个查询翻译管道,但目前甚至不打算将其发布3.0版。

目前,您没有其他选择。您可以尝试自己处理查询表达式树,但这是一个复杂的任务,您可能会发现为什么尚未实现它:)如果您可以将查询转换为合并了Where条件的等效单查询,则申请Include就可以了。


P.S。请注意,即使是现在,您的方法在技术上也没有“ Include”的“效果”,在客户端评估方法上要精益求精,这使其绝对不等同于相应的单个查询。