2012-12-19 14 views
6

Ci sono da 0 a n reparti nella mia azienda, da 0 a n uffici in 1 reparto e da 0 a n dipendenti in 1 ufficio. Ora ho bisogno di una query usando linq per elencare l'età media di emplyees reparto, se nessuno in un reparto, allora la media di default è 0. codice è qui sotto:Query di join esterno tramite LINQ alle entità

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(); 

Ma come combinare q0 e q1 a una query?

+2

Ecco un buon articolo su come rendere unisce con LINQ: http://www.codeproject.com/Articles/488643/LinQ-Extended-Joins –

+0

Estensione perfetta. Ma sono metodi, non linq fluenti. – user1729842

risposta

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

cambiato a:

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

Addendum: vorrei utilizzare un sub-select per abbinare il nome in più, non conoscendo il layout db ho improvvisato dal codice, ma si potrebbe renderlo più efficiente e avere un join multipart basato anche sui sottoselezionamenti. Scusa, non posso testare questo codice al lavoro, posso approssimare abbastanza bene, ma avrei bisogno di qualche informazione in più su dove si trovano i nomi dei tuoi dipartimenti se hai bisogno di una risposta più dettagliata :) Ho cambiato i join esterni di sinistra ai join, scusa Ho dimenticato in C# con linq è possibile utilizzare DefaultIfEmpty() per causare un comportamento di join sinistro esterno nel codice.

Un join di sinistra esterno restituirà valori null in cui non ci sono valori corrispondenti, ma consentirà il ritorno su qualsiasi parte che abbia un valore corrispondente. Unisciti comunque non restituirà alcuna voce nulla che sospetto sia il motivo per cui hai avuto le due domande?

L'unica avvertenza sulla query che ho presentato è che è necessario inserire tutti i valori necessari prima di utilizzarli se sono nulli, ad esempio DepartmentId avrà bisogno di una logica per popolarlo nel caso in cui DE sia nullo.

+0

Penso che potresti modificare questo un po 'più per inserire la parte nome e quindi credo che la seconda query degli OP non sia necessaria. – pstrjds

+2

join esterno sinistro è una buona soluzione. Ma non è sintassi linq valida, se la sintassi è valida, le 3 parole saranno blu come parola chiave C#. – user1729842

0

Grazie a tutti, ho avuto la risposta:

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