LINQ-왼쪽 조인, 그룹화 및 카운트


166

이 SQL이 있다고 가정 해 봅시다.

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

이것을 LINQ to SQL로 어떻게 번역 할 수 있습니까? COUNT (c.ChildId)에 멈춰 생성 된 SQL이 항상 COUNT (*)를 출력하는 것 같습니다. 내가 지금까지 얻은 것입니다 :

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

감사합니다!

답변:


189
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) }

그래, 그게 효과가 있지만 왜? 당신은 그것을 어떻게 생각하십니까? null 값을 세지 않으면 어떻게 COUNT (c.ChildId)와 동일합니까? 감사.
pbz

4
이것이 SQL이 작동하는 방식입니다. COUNT (fieldname)은 해당 필드에서 널이 아닌 행을 계산합니다. 어쩌면 나는 당신의 질문을 얻지 못할 것입니다. 그렇다면 분명히하십시오.
Mehrdad Afshari

나는 항상 행 수를 계산할 때 그것에 대해 생각했지만, 널이 아닌 값만 계산됩니다. 감사.
pbz

1
.Count ()는 COUNT (*)를 생성하여 그 그룹의 모든 행을 계산합니다.
Mehrdad Afshari

나는 똑같은 문제가 있었지만 t => t.ChildID! = null을 비교하면 나에게 효과가 없었습니다. 결과는 항상 null 객체였으며 Resharper는 표현식이 항상 참이라고 불평했습니다. 그래서 (t => t! = null) 사용하고 저에게 효과적이었습니다.
Joe

55

하위 쿼리 사용을 고려하십시오.

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

쿼리 유형이 연결에 의해 연결되면 다음과 같이 단순화됩니다.

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

내가 올바르게 기억한다면 (그것은 오래되었습니다), 그 쿼리는 큰 것의 단순화 된 버전이었습니다. 내가 필요한 전부가 열쇠 였고 솔루션이 더 깨끗했을 것입니다.
pbz

1
귀하의 의견은 원래의 질문과 답이 올린 답변과 관련이 없습니다. 또한-키보다 많은 것을 원하면 전체 부모 행을 그릴 수 있습니다.
Amy B

let키워드가 있는 솔루션 은 @Mosh 그룹 가입 솔루션과 동일한 하위 쿼리를 생성합니다.
Mohsen Afshin

@MohsenAfshin 네, 그것은 바로 위에 내 답변에 하위 쿼리가있는 쿼리와 동일한 하위 쿼리를 생성합니다.
Amy B

39

늦은 답변 :

당신은 가입 왼쪽을 필요가 없습니다 당신이하고있는 모든 카운트 인 경우 모두에서 (). 주 join...into사실로 번역되어 GroupJoin있는 같은 그룹 반환 new{parent,IEnumerable<child>}방금 호출 할 필요가 있으므로 Count()그룹에를 :

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

확장 메소드 구문에서 a join into는 is와 같지만 GroupJoin( is는 join없는 intois Join) :

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

8

LINQ 구문의 기본 개념은 SQL 구문을 에뮬레이트하는 것이지만 SQL 코드를 LINQ로 직접 변환하는 것을 항상 생각해서는 안됩니다. 이 특정 경우에 조인 은 그룹 조인 자체 이기 때문에 그룹에 참여할 필요가 없습니다 .

내 해결책은 다음과 같습니다.

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

여기에서 가장 많이 투표 된 솔루션과 달리 Count (t => t.ChildId! = null) 에서 j1 , j2 및 null 검사 가 필요하지 않습니다 .


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) })
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.