简体   繁体   English

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

[英]Linq Join hierarchy (one to many)

I have 3 entities, Computer, Monitor and PortNumber. 我有3个实体,Computer,Monitor和PortNumber。 The entity monitor has a foreign key which references the entity computer while the entity PortNumber has a foreign key which references the entity Monitor. 实体监视器具有引用实体计算机的外键,而实体PortNumber具有引用实体Monitor的外键。 The following rules apply 以下规则适用

  • A computer can have many monitors but a monitor can only belong to one computer. 计算机可以有许多显示器,但显示器只能属于一台计算机。
  • A monitor can have many many port numbers but a port number can only belong to one monitor 监视器可以有许多端口号,但端口号只能属于一个监视器

I want to write a Join to to show the number the number of monitor and ports(monitor ports) for each computer. 我想编写一个Join来显示每台计算机的监视器和端口(监视器端口)的数量。 I am able to join two entities with the groupjoin but can't figure out how to add the 3rd entity. 我可以使用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()});

How can I add the 3rd entity? 如何添加第3个实体? Here is some executable code: http://dotnetfiddle.net/L1TBgJ 这是一些可执行代码: http//dotnetfiddle.net/L1TBgJ

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(),
    };

I think this is the kind of thing you are looking for. 我认为这是你要找的东西。 The second join means that you will need to make sure you call distinct on those items not included in the grouping. 第二个连接意味着您需要确保对未包含在分组中的项目调用distinct。 If the collection of ports exists on the monitor object. 如果监视器对象上存在端口集合。 Then you will just need to nest the second part of the query. 然后你只需要嵌套查询的第二部分。

If the ports are a collection on the monitor and you want to flatten them to link to computers. 如果端口是监视器上的集合,并且您希望将它们展平以链接到计算机。 I think something like this should do it. 我觉得这样的事情应该做到。

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(),
    };

Since you have the associations set up correctly in your EF Model you shouldn't need the joins at all. 由于您在EF模型中正确设置了关联,因此根本不需要连接。 You should be able to do this simply as: 您应该能够这样做:

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

I do notice in your test script where you are using objects, you are not instantiating the monitors and ports arrays and setting them to the objects you added. 我注意到在您使用对象的测试脚本中,您没有实例化监视器和端口阵列并将它们设置为您添加的对象。 If you're using code-first EF for this (as I suspect you are), those values will be set when actually issuing the query against a database. 如果你正在使用代码优先EF(我怀疑你是),那么在实际向数据库发出查询时将设置这些值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM