Вопрос

I have 3 entities, Computer, Monitor and 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. 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. I am able to join two entities with the groupjoin but can't figure out how to add the 3rd entity.

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? Here is some executable code: http://dotnetfiddle.net/L1TBgJ

Это было полезно?

Решение

Since you have the associations set up correctly in your EF Model you shouldn't need the joins at all. 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.

Другие советы

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. 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(),
    };
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top