C# 使用LINQ到实体的外部联接查询

C# 使用LINQ到实体的外部联接查询,c#,linq,entity-framework,linq-to-entities,C#,Linq,Entity Framework,Linq To Entities,我的公司有0到n个部门,1个部门有0到n个办公室,1个办公室有0到n个员工。现在我需要使用linq查询,按部门列出员工的平均年龄,如果部门中没有人,则默认平均年龄为0。 代码如下: DataContext ctx = new DataContext(); var q0 = from d in ctx.Departments join o in ctx.Offices on d.Id equals o.DepartmentId

我的公司有0到n个部门,1个部门有0到n个办公室,1个办公室有0到n个员工。现在我需要使用linq查询,按部门列出员工的平均年龄,如果部门中没有人,则默认平均年龄为0。 代码如下:

    DataContext ctx = new DataContext();

    var q0 = from d in ctx.Departments
             join o in ctx.Offices on d.Id equals o.DepartmentId
             join e in ctx.Employees on o.Id equals e.OfficeId
             group e by d into de
             select new {
                DepartmentId = de.Key.Id,
                AverageAge = de.Count() == 0 ? 0 : de.Average(e => e.Age),
             };


    var q1 = from d in ctx.Departments
             join de in q0 on d.Id equals de.DepartmentId into des
             from de in des.DefaultIfEmpty()
             select new
             {
                 DepartmentName = d.Name,
                 AverageAge = de == null ? 0 : de.AverageAge
             };

    var result = q1.ToList();
    foreach (var item in result)
    {
        Console.WriteLine("{0}-{1}", item.DepartmentName, item.AverageAge);
    }
    ctx.Dispose();
但是如何将q0和q1组合到一个查询中呢

    were you meaning something along the lines of:

var newQ2 = from d in ctx.Departments
                 outer left join o in ctx.Offices on d.Id equals o.DepartmentId
                 outer left join e in ctx.Employees on o.Id equals e.OfficeId
                 group e by d into de
                 select new {
                    DepartmentId = de.Key.Id,
                    AverageAge = de.Count() == 0 ? 0 : de.Average(e => e.Age),
                 };
改为:

var newQ2 = from d in ctx.Departments
                     join o in ctx.Offices on d.Id equals o.DepartmentId
                     join e in ctx.Employees on o.Id equals e.OfficeId
                     group e by d into de.DefaultIfEmpty()
                     select new {
                        DepartmentId = de.Key.Id,
                        DepartdentName = select d.Name from d where d.id = de.Key.Id,
                        AverageAge = de.Count() == 0 ? 0 : de.Average(e => e.Age),
                     };
附录:我会使用子选择来匹配额外的名称,不知道我从代码中临时制作的db布局,但您可以使其更有效,并基于子选择进行多部分连接。抱歉,我无法在工作中测试此代码,我可以很好地估计,但如果您需要更详细的答案,则需要有关您的部门名称所在位置的更多信息:我已将左外连接更改回连接,抱歉,我忘记了在c和linq中,您可以使用DefaultIfEmpty在代码中导致左外连接行为

外部左联接将在没有相应值的情况下返回null,但将允许在具有相应值的任何部分上返回。但是Join不会返回任何空条目,我怀疑这就是为什么会有这两个查询


对于我提出的查询,唯一需要注意的是,如果值为null,则在使用它们之前,您需要填充所需的任何值。例如,如果DE为null,DepartmentId将需要一些逻辑来填充它。

谢谢大家,我已经得到了答案:

        var q1 = 
                 from d in ctx.Departments 
                 from o in ctx.Offices.Where(o => o.DepartmentId == d.Id).DefaultIfEmpty()
                 from e in ctx.Employees.Where(e =>  e.OfficeId == o.Id).DefaultIfEmpty()
                 group e by d into de
                 select new {
                    DepartmentName = de.Key.Name,
                    AverageAge = de.Average(e => e == null ? 0 : e.Age),
                 };

这是一篇关于使用LINQ:Perfect extension进行连接的好文章。但是它们是方法,不是流畅的LINQ。我认为您可以进一步修改这篇文章,以引入名称部分,然后我相信OPs第二个查询是不必要的。外部左连接是一个很好的解决方案。但是它不是有效的LINQ语法,如果语法有效,这三个单词将以蓝色作为c关键字。