LINQ Join con múltiples condiciones en la cláusula On

93

Estoy tratando de implementar una consulta en LINQ que usa una combinación externa izquierda con múltiples condiciones en la cláusula ON.

Usaré el ejemplo de las siguientes dos tablas Proyecto (ProjectID, ProjectName) y Task (TaskID, ProjectID, TaskName, Completed). Quiero ver la lista completa de todos los proyectos con sus respectivas tareas, pero solo aquellas tareas que se completaron.

No puedo usar un filtro para Completed == trueporque eso filtrará cualquier proyecto que no tenga tareas completadas. En su lugar, quiero agregar Completed == truea la cláusula ON de la combinación para que se muestre la lista completa de proyectos, pero solo se mostrarán las tareas completadas. Los proyectos sin tareas completadas mostrarán una sola fila con un valor nulo para Task.

Aquí está la base de la 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 }

¿Cómo agrego && t2.Completed == truea la cláusula on?

Parece que no puedo encontrar ninguna documentación LINQ sobre cómo hacer esto.

Kuyenda
fuente
Respuesta relacionada aquí usando la sintaxis Lambda
StuartLC

Respuestas:

130

Solo necesita nombrar la propiedad anónima de la misma manera en ambos lados

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

Según los comentarios de @svick, aquí hay otra implementación que podría tener más 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
fuente
2
Parece una forma no obvia de hacerlo. No estoy seguro de entender lo que se supone que debe hacer.
svick
1
@svick: el uso de tipos anónimos le permite unirse en varios criterios. Solo necesita asegurarse de que los nombres de las propiedades coincidan en ambos tipos. ¿No estás seguro de dónde viene la confusión?
Aducci
La confusión es que realmente tiene más sentido como dos igualdades unidas and, no como una igualdad de algún objeto "extraño". Y para probar mi punto, su código es incorrecto. Para que funcione, deberías tener trueen el lado izquierdo y t2.Completeen el derecho.
svick
1
Gracias Aducci. Tuve que intercambiar lados en la consulta para obtener el contexto correcto, pero funcionó. Este problema está simplificado, y en mi problema del mundo real no es solo SecondProperty es verdadero o falso, SecondProperty es un número entero y yo uso AND SecondProperty IN (123, 456). Continuaré con ese desafío y cualquier ayuda que pueda brindar será muy apreciada.
Kuyenda
@svick - Buen truco, cambié el orden de t2.Completed y el valor verdadero . Agregué otra solución que podría ser menos extraña para ti.
Aducci
39

Aquí tienes:

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
fuente
Esto parece más comprensible.
Bijay Yadav
1

No puedes hacerlo así. La joincláusula (y el Join()método de extensión) solo admite equijoins. Esa es también la razón por la que se usa equalsy no ==. E incluso si pudiera hacer algo así, no funcionaría, porque joines una combinación interna, no externa.

svick
fuente
No se solicitó la unión externa y (ver otras respuestas), obviamente puede hacerlo.
edc65
0

Esto funciona bien para 2 mesas. Tengo 3 tablas y la cláusula on tiene que vincular 2 condiciones de 3 tablas. Mi código:

de p en _dbContext.Products une pv en _dbContext.ProductVariants en p.ProduktId es igual a pv.ProduktId une jpr en leftJoinQuery en el nuevo {VariantId = pv.Vid, ProductId = p.ProduktId} es igual a nuevo {VariantId = jpr.Prices.VariantId ProductId = jpr.Prices.ProduktID} en lj

Pero muestra un error en este punto: únase pv en _dbContext.ProductVariants en p.ProduktId es igual a pv.ProduktId

Error: el tipo de una de las expresiones en la cláusula de unión es incorrecto. Error de inferencia de tipo en la llamada a 'GroupJoin'.

OracleNovice
fuente