2009-03-29 15 views
157

Digamos que tengo este SQL:LINQ - combinación izquierda, Grupo A, y el conde

SELECT p.ParentId, COUNT(c.ChildId) 
FROM ParentTable p 
    LEFT OUTER JOIN ChildTable c ON p.ParentId = c.ChildParentId 
GROUP BY p.ParentId 

¿Cómo puedo traducir esto en LINQ to SQL? Me quedé atrapado en el COUNT (c.ChildId), el SQL generado siempre parece dar como resultado COUNT (*). Esto es lo que obtuve hasta ahora:

from p in context.ParentTable 
join c in context.ChildTable on p.ParentId equals c.ChildParentId into j1 
from j2 in j1.DefaultIfEmpty() 
group j2 by p.ParentId into grouped 
select new { ParentId = grouped.Key, Count = grouped.Count() } 

¡Gracias!

Respuesta

179
from p in context.ParentTable 
join c in context.ChildTable on p.ParentId equals c.ChildParentId into j1 
from j2 in j1.DefaultIfEmpty() 
group j2 by p.ParentId into grouped 
select new { ParentId = grouped.Key, Count = grouped.Count(t=>t.ChildId != null) } 
+0

OK, eso funciona, pero ¿por qué? ¿Cómo piensas a través de eso? ¿Cómo el conteo de valores nulos nos da lo mismo que COUNT (c.ChildId)? Gracias. – pbz

+4

Así es como funciona SQL. COUNT (fieldname) contará las filas en ese campo que no son nulas. Tal vez no entiendo tu pregunta, aclara si ese es el caso. –

+0

Supongo que siempre pensé en ello en términos de recuento de filas, pero está en lo cierto, solo se cuentan los valores no nulos. Gracias. – pbz

7
(from p in context.ParentTable  
    join c in context.ChildTable 
    on p.ParentId equals c.ChildParentId into j1 
    from j2 in j1.DefaultIfEmpty() 
    select new { 
      ParentId = p.ParentId, 
     ChildId = j2==null? 0 : 1 
     }) 
    .GroupBy(o=>o.ParentId) 
    .Select(o=>new { ParentId = o.key, Count = o.Sum(p=>p.ChildId) }) 
55

Considere el uso de una subconsulta:

from p in context.ParentTable 
let cCount = 
(
    from c in context.ChildTable 
    where p.ParentId == c.ChildParentId 
    select c 
).Count() 
select new { ParentId = p.Key, Count = cCount } ; 

Si los tipos de consulta están conectados por una asociación, esto simplifica a:

from p in context.ParentTable 
let cCount = p.Children.Count() 
select new { ParentId = p.Key, Count = cCount } ; 
+0

Si no recuerdo mal (ha pasado un tiempo), esa consulta era una versión simplificada de una grande. Si todo lo que necesitaba es la clave y cuente que su solución hubiera sido más limpia/mejor. – pbz

+1

Su comentario no tiene sentido en el contexto de la pregunta original y las respuestas subidas de tono. Además, si desea más que la clave, tiene la fila principal para dibujar. –

+0

esto me ayuda con un problema algo relacionado, gracias – Merritt

26

RESPUESTA LATE:

Usted no debería necesitar la combinación izquierda si todo lo que está haciendo es Contar(). Tenga en cuenta que join...into en realidad se traduce a GroupJoin que devuelve agrupaciones como new{parent,IEnumerable<child>} por lo que sólo necesitan llamar Count() en el grupo:

from p in context.ParentTable 
join c in context.ChildTable on p.ParentId equals c.ChildParentId into g 
select new { ParentId = p.Id, Count = g.Count() } 

En Método de extensión sintaxis de un join into es equivalente a GroupJoin (mientras que un join sin un into es Join):

context.ParentTable 
    .GroupJoin(
        inner: context.ChildTable 
     outerKeySelector: parent => parent.ParentId, 
     innerKeySelector: child => child.ParentId, 
      resultSelector: (parent, children) => new { parent.Id, Count = children.Count() } 
    ); 
+1

Esa es una solución hermosa y simple para el problema, ¡gracias! –

+0

esto es mejor que otras soluciones y debería ser la respuesta a esta pregunta. –

5

Mientras que la idea detrás de la sintaxis de LINQ es emular la sintaxis SQL, no siempre se debe pensar de traducir directamente el código SQL en LINQ. En este caso particular, no es necesario que hagamos group en ya que join in es un grupo join.

aquí está mi solución:

from p in context.ParentTable 
join c in context.ChildTable on p.ParentId equals c.ChildParentId into joined 
select new { ParentId = p.ParentId, Count = joined.Count() } 

A diferencia de la mayoría votaron solución a este problema, que no necesitamos J1, j2 y la comprobación nulo en Conde (t => t.ChildId! = Null)

Cuestiones relacionadas