【问题标题】:Outer join query using LINQ to Entities [duplicate]使用 LINQ to Entities 的外部连接查询 [重复]
【发布时间】:2012-12-19 08:11:53
【问题描述】:

我公司有 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 组合到一个查询中呢?

【问题讨论】:

标签: c# linq entity-framework linq-to-entities


【解决方案1】:

你的意思是:

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 将需要一些逻辑来填充它。

【讨论】:

  • 我认为您可以进一步修改这个以引入名称部分,然后我认为 OP 的第二个查询是不必要的。
  • outer left join 是一个很好的解决方案。但是它不是有效的 linq 语法,如果语法是有效的,这 3 个单词将被蓝色作为 c# 关键字。
  • 我不明白这个答案是如何被如此频繁地投票的。这是无效的代码,难以理解。
【解决方案2】:

谢谢大家,我有答案了:

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-02-07
    • 1970-01-01
    • 2012-04-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-13
    相关资源
    最近更新 更多