使用LINQ to Entities的外连接查询

时间:2012-12-19 08:11:53

标签: 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
             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组合成一个查询?

2 个答案:

答案 0 :(得分:7)

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

附录:我会使用一个子选择来匹配额外的名称,不知道你的代码中我即兴创建的数据库布局,但是你可以使它更高效并且还有基于子选择的多部分连接。对不起,我不能在工作中测试这个代码,我可以很好地估计,但如果你需要更详细的答案,需要更多关于你的部门名称所在位置的信息:)我已经将左外连接更改回连接,抱歉我忘记在c#中使用linq你可以使用DefaultIfEmpty()在代码中引起外部左连接行为。

外部左连接将返回没有相应值的空值,但允许返回具有相应值的任何部分。但是,加入不会返回任何空条目,我怀疑这是为什么你有两个查询?

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

答案 1 :(得分:0)

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

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