2012-12-19 34 views
6

我公司有0到n個部門,1個部門有0到n個辦公室,1個辦公室有0到n個辦公室。現在我需要一個使用linq來查詢僱員平均年齡的查詢部門,如果沒有人在一個部門則默認平均爲0。 代碼如下:使用LINQ到實體的外部聯接查詢

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

下面是關於制定好文章與LINQ聯接:http://www.codeproject.com/Articles/488643/LinQ-Extended-Joins –

+0

完美的擴展。但他們是方法,而不是流利的linq。 – user1729842

回答

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

附錄:我會用一個子選擇匹配了額外的名字,不知道你的數據庫佈局我從你的代碼即興的,但你可以使它更有效率,並且還有基於子選擇的多部分連接。對不起,我不能在工作中測試這個代碼,我可以近似相當好,但如果您需要更詳細的答案,需要更多關於您的部門名稱所在位置的信息:)我已將外部左連接更改回連接,對不起我忘記了在LINQ的C#中,你可以使用DefaultIfEmpty()在代碼中引起外部左連接行爲。

在沒有相應值的情況下,外部左連接將返回空值,但將允許具有相應值的任何部分返回。但是,加入不會返回任何空的條目,我懷疑這是爲什麼你有兩個查詢?

我提出的查詢中唯一需要注意的是,在使用它們之前,如果它們是空值,則需要填充所需的任何值,例如,DepartmentId在DE爲空時需要一些邏輯來填充它。

+0

我想你可以修改這個稍微拉一點名字部分,然後我相信OP的第二個查詢是不必要的。 – pstrjds

+2

外部左連接是一個很好的解決方案。但它不是有效的linq語法,如果語法有效,那麼3個單詞將作爲c#關鍵詞藍色。 – user1729842

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