LINQ Join con più condizioni nella clausola On


93

Sto cercando di implementare una query in LINQ che utilizza un join esterno sinistro con più condizioni nella clausola ON.

Userò l'esempio delle seguenti due tabelle Project (ProjectID, ProjectName) e Task (TaskID, ProjectID, TaskName, Completed). Voglio vedere l'elenco completo di tutti i progetti con le rispettive attività, ma solo quelle che sono state completate.

Non posso usare un filtro per Completed == trueperché filtrerà tutti i progetti che non hanno attività completate. Invece voglio aggiungere Completed == truealla clausola ON del join in modo che venga mostrato l'elenco completo dei progetti, ma verranno mostrate solo le attività completate. I progetti senza attività completate mostreranno una singola riga con un valore nullo per Attività.

Ecco le basi della query.

from t1 in Projects
join t2 in Tasks
on new { t1.ProjectID} equals new { t2.ProjectID } into j1
from j2 in j1.DefaultIfEmpty()
select new { t1.ProjectName, t2.TaskName }

Come aggiungo && t2.Completed == truealla clausola on?

Non riesco a trovare alcuna documentazione LINQ su come eseguire questa operazione.


Risposta correlata qui utilizzando la sintassi Lambda
StuartLC

Risposte:


130

Hai solo bisogno di nominare la proprietà anonima allo stesso modo su entrambi i lati

on new { t1.ProjectID, SecondProperty = true } equals 
   new { t2.ProjectID, SecondProperty = t2.Completed } into j1

Sulla base dei commenti di @svick, ecco un'altra implementazione che potrebbe avere più senso:

from t1 in Projects
from t2 in Tasks.Where(x => t1.ProjectID == x.ProjectID && x.Completed == true)
                .DefaultIfEmpty()
select new { t1.ProjectName, t2.TaskName }

2
Sembra un modo non ovvio per farlo. Non sono sicuro di capire cosa dovrebbe fare.
svick

1
@svick: l'utilizzo di tipi anonimi ti consente di partecipare a più criteri. Devi solo assicurarti che i nomi delle proprietà corrispondano su entrambi i tipi. Non sei sicuro da dove provenga la confusione?
Aducci

La confusione è che ha davvero più senso come due uguaglianze unite da and, non un'uguaglianza di qualche oggetto "strano". E per dimostrare il mio punto, il tuo codice è sbagliato. Perché funzioni, dovresti avere truesul lato sinistro e t2.Completesulla destra.
svick

1
Grazie Aducci. Ho dovuto scambiare i lati della query per ottenere il contesto corretto, ma ha funzionato. Questo problema è semplificato e nel mio problema del mondo reale non è solo SecondProperty vero o falso, SecondProperty è un numero intero e io uso AND SecondProperty IN (123, 456). Passerò a questa sfida e qualsiasi aiuto che potresti dare sarebbe molto apprezzato.
Kuyenda

@svick - Buona cattura, ho cambiato l'ordine di t2.Completed e il valore vero . Ho aggiunto un'altra soluzione che potrebbe essere meno strana per te.
Aducci

39

Ecco qui:

from b in _dbContext.Burden 
join bl in _dbContext.BurdenLookups on
new { Organization_Type = b.Organization_Type_ID, Cost_Type = b.Cost_Type_ID } equals
new { Organization_Type = bl.Organization_Type_ID, Cost_Type = bl.Cost_Type_ID }

Questo sembra più comprensibile.
Bijay Yadav

1

Non puoi farlo così. La joinclausola (e il Join()metodo di estensione) supporta solo equijoin. Questo è anche il motivo per cui usa equalse non ==. E anche se potessi fare qualcosa del genere, non funzionerebbe, perché joinè un join interno, non un join esterno.


L'unione esterna non è stata richiesta e (vedi altre risposte), ovviamente puoi.
edc65

0

Funziona bene per 2 tavoli. Ho 3 tabelle e sulla clausola devo collegare 2 condizioni da 3 tabelle. Il mio codice:

da p in _dbContext.Products unirsi a pv in _dbContext.ProductVariants su p.ProduktId è uguale a pv.ProduktId unirsi a jpr in leftJoinQuery su new {VariantId = pv.Vid, ProductId = p.ProduktId} è uguale a new {jprariantIdices, ProductId = jpr.Prices.ProduktID} in lj

Ma a questo punto viene visualizzato un errore: join pv in _dbContext.ProductVariants su p.ProduktId è uguale a pv.ProduktId

Errore: il tipo di una delle espressioni nella clausola di join non è corretto. Inferenza del tipo non riuscita nella chiamata a "GroupJoin".

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.