Linq加入层次结构(一对多)

问题描述:

我有3个实体,计算机,监视器和端口号。实体监视器有一个引用实体计算机的外键,而实体端口号有一个引用实体监视器的外键。以下规则适用Linq加入层次结构(一对多)

  • 一台计算机可以有许多显示器,但显示器只能属于一个 计算机。
  • 监视器可以有很多很多的端口号,但是端口 号只能属于一个监控

我想写一个加入到显示数量的监控和端口(监控端口)的数每台电脑。我能够与groupjoin加入两个实体,但无法弄清楚如何添加第三个实体。

var v = Ports.GroupJoin(Monitors, c => c.ComputerId, m => m.ComputerId, 
     (c, m) => new{c, m}) 
     .select(s => new { 
      Computer = c.ComputerProp, 
      Monitors = m.Sum()}); 

如何添加第三个实体? 下面是一些可执行代码:http://dotnetfiddle.net/L1TBgJ

+0

这在查询语法中读/查更容易。 – tigerswithguitars

+0

你是什么意思? – jpo

+0

已添加答案,因此我有更多空间可供展示。这可能是你需要的,请告知。 – tigerswithguitars

由于您在EF模型中设置了正确的关联,所以根本不需要连接。你应该能够做到这一点简单地为:

var v = Computers 
     .Select(c => new { 
      Computer = c.ComputerProp, 
      Monitors = c.monitors.Count(), // note: not Sum(), 
      Ports = c.monitors.Sum(m => m.ports.Count()) 
     }); 

我通知你的测试脚本,你正在使用的对象,你是不是实例化监控和端口的阵列,并将它们设置为你添加的对象。如果您使用的是代码优先的EF(因为我怀疑自己是这样),那么在实际针对数据库发出查询时会设置这些值。

+0

哇。谢谢!你是对的。我使用的是代码优先的EF,我不必进行连接。 – jpo

+0

这很酷。我更习惯于LINQ,我认为你必须跳过更多的箍环来获得简洁。从未尝试EF,但可能现在:)。 – tigerswithguitars

var v = 
    from c in Computers 

    // First outer join. 
    join m in Monitors on c.ComputerId equals m.ComputerId into monitor 
    from m in monitors.DefaultIfEmpty() 

    // Second outer join. 
    join p in Ports on m.PortId equals p.PortId into port 
    from p in port.DefaultIfEmpty() 

    // Group by the computers 
    group new { m, p } by new { c } into g 
    select new 
    { 
     Computer = g.Key.c, 
     Monitors = g.Select(i => i.m).Distinct().ToList(), 
     Ports = g.Select(i => i.p).Distinct().ToList(), 
    }; 

我认为这是你正在寻找的那种东西。第二次加入意味着您需要确保对不包含在分组中的项目进行区分。如果端口集合存在于监视器对象上。那么你只需要嵌套查询的第二部分。

如果这些端口是显示器上的一个集合,并且您希望将它们拼合成链接到计算机。我认为这样的事情应该这样做。

var v = 
    from c in Computers 

    // First outer join. 
    join m in Monitors on c.ComputerId equals m.ComputerId into monitor 
    from m in monitors.DefaultIfEmpty() 

    // Group by the computers 
    group new { m } by new { c } into g 
    select new 
    { 
     Computer = g.Key.c, 
     Ports = g.Select(i => i.m).SelectMany(i => i.Port).ToList(), 
    }; 
+0

谢谢!这有助于。我通过行得到错误(无法将lambda表达式转换为类型System.Collections.Generic.IEqualityComparer ',因为它不是委托类型) – jpo

+0

我注意到这个组中的一个小错误可能有所帮助。但是如果没有你的确切代码,这很难。如果可以,请创建一个http://dotnetfiddle.net/ – tigerswithguitars

+0

在这里:http://dotnetfiddle.net/kkoOQc。这些数字是错误的 – jpo