LINQ Join com múltiplas condições na cláusula On

93

Estou tentando implementar uma consulta em LINQ que usa uma junção externa esquerda com várias condições na cláusula ON.

Usarei o exemplo das duas tabelas a seguir, Project (ProjectID, ProjectName) e Task (TaskID, ProjectID, TaskName, Completed). Quero ver a lista completa de todos os projetos com suas respectivas tarefas, mas apenas as tarefas que foram concluídas.

Não posso usar um filtro para Completed == trueporque isso filtrará quaisquer projetos que não tenham tarefas concluídas. Em vez disso, desejo adicionar Completed == trueà cláusula ON da junção para que a lista completa de projetos seja mostrada, mas apenas as tarefas concluídas sejam mostradas. Projetos sem tarefas concluídas mostrarão uma única linha com um valor nulo para Tarefa.

Aqui está a base da consulta.

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 }

Como faço && t2.Completed == truepara adicionar à cláusula on?

Não consigo encontrar nenhuma documentação do LINQ sobre como fazer isso.

Kuyenda
fonte
Resposta relacionada aqui usando sintaxe Lambda
StuartLC

Respostas:

130

Você só precisa nomear a propriedade anônima da mesma forma em ambos os lados

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

Com base nos comentários de @svick, aqui está outra implementação que pode fazer mais sentido:

from t1 in Projects
from t2 in Tasks.Where(x => t1.ProjectID == x.ProjectID && x.Completed == true)
                .DefaultIfEmpty()
select new { t1.ProjectName, t2.TaskName }
Aducci
fonte
2
Essa parece uma maneira não óbvia de fazer isso. Não tenho certeza se entenderia o que ele deve fazer.
svick,
1
@svick - O uso de tipos anônimos permite que você se junte em vários critérios. Você só precisa ter certeza de que os nomes das propriedades correspondem aos dois tipos. Não tem certeza de onde está vindo a confusão?
Aducci,
A confusão é que realmente faz mais sentido como duas igualdades unidas por and, e não uma igualdade de algum objeto “estranho”. E para provar meu ponto, seu código está errado. Para funcionar, você teria que ter truedo lado esquerdo e do lado t2.Completedireito.
svick
1
Obrigado Aducci. Tive que trocar os lados da consulta para obter o contexto correto, mas funcionou. Este problema é simplificado, e no meu problema do mundo real não é apenas SecondProperty é verdadeiro ou falso, SecondProperty é um número inteiro e eu uso AND SecondProperty IN (123, 456). Vou passar para esse desafio e qualquer ajuda que você possa dar seria muito apreciada.
Kuyenda,
@svick - Boa captura, troquei a ordem do t2.Completed e o valor verdadeiro . Eu adicionei outra solução que pode ser menos estranha para você.
Aducci,
39

Aqui está:

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 }
Nalan Madheswaran
fonte
Isso parece mais compreensível.
Bijay Yadav de
1

Você não pode fazer assim. A joincláusula (e o Join()método de extensão) oferece suporte apenas a equijoins. Essa também é a razão, porque usa equalse não usa ==. E mesmo se você pudesse fazer algo assim, não funcionaria, porque joiné uma junção interna, não externa.

Svick
fonte
A junção externa não foi solicitada e (veja outras respostas), obviamente você pode.
edc65
0

Isso funciona bem para 2 tabelas. Tenho 3 tabelas e a cláusula on tem de vincular 2 condições de 3 tabelas. Meu código:

de p em _dbContext.Products juntar pv em _dbContext.ProductVariants em p.ProduktId é igual a pv.ProduktId juntar jpr em leftJoinQuery em novo {VariantId = pv.Vid, ProductId = p.ProduktId} é igual a novo {VariantId = jpr.Prices.Variant ProductId = jpr.Prices.ProduktID} em lj

Mas está mostrando um erro neste ponto: junte pv em _dbContext.ProductVariants em p.ProduktId é igual a pv.ProduktId

Erro: o tipo de uma das expressões na cláusula de junção está incorreto. A inferência de tipo falhou na chamada para 'GroupJoin'.

OracleNovice
fonte