LINQ - Tham gia trái, Nhóm theo và Đếm


166

Giả sử tôi có SQL này:

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

Làm thế nào tôi có thể dịch cái này sang LINQ sang SQL? Tôi đã bị kẹt tại COUNT (c.ChildId), SQL được tạo dường như luôn xuất ra COUNT (*). Đây là những gì tôi đã nhận được cho đến nay:

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

Cảm ơn bạn!

Câu trả lời:


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

OK, nó hoạt động, nhưng tại sao? Bạn nghĩ thế nào về nó? Làm thế nào để không đếm các giá trị null cho chúng ta giống như COUNT (c.ChildId)? Cảm ơn.
pbz

4
Đây là cách SQL hoạt động. COUNT (tên trường) sẽ đếm các hàng trong trường đó không phải là null. Có lẽ tôi không nhận được câu hỏi của bạn, xin vui lòng làm rõ nếu đó là trường hợp.
Mehrdad Afshari

Tôi đoán tôi luôn nghĩ về điều đó khi đếm hàng, nhưng bạn nói đúng, chỉ có các giá trị khác không được tính. Cảm ơn.
pbz

1
.Count () sẽ tạo ra COUNT (*) sẽ đếm tất cả các hàng trong nhóm đó.
Mehrdad Afshari

Tôi đã có cùng một vấn đề chính xác tuy nhiên so sánh t => t.ChildID! = Null không làm việc cho tôi. Kết quả luôn là một đối tượng null và Resharper phàn nàn rằng biểu thức luôn luôn đúng. Vì vậy, tôi đã sử dụng (t => t! = Null) và điều đó đã làm việc cho tôi.
Joe

55

Xem xét sử dụng truy vấn con:

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

Nếu các loại truy vấn được kết nối bởi một liên kết, điều này đơn giản hóa thành:

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

Nếu tôi nhớ chính xác (đã được một lúc), truy vấn đó là phiên bản đơn giản hóa của một câu hỏi lớn. Nếu tất cả những gì tôi cần là chìa khóa và tính giải pháp của bạn sẽ sạch hơn / tốt hơn.
pbz

1
Nhận xét của bạn không có ý nghĩa trong ngữ cảnh với câu hỏi ban đầu và câu trả lời nâng cao. Ngoài ra - nếu bạn muốn nhiều hơn khóa, bạn có toàn bộ hàng cha mẹ để rút ra.
Amy B

Giải pháp với lettừ khóa sẽ tạo ra một truy vấn con giống như giải pháp tham gia nhóm @Mosh.
Mohsen Afshin

@MohsenAfshin có, nó tạo ra một truy vấn con giống như truy vấn với một truy vấn con trong câu trả lời của tôi ngay trên nó.
Amy B

39

CÂU TRẢ LỜI MUỘN:

Bạn hoàn toàn không cần tham gia bên trái nếu tất cả những gì bạn đang làm là Count (). Lưu ý rằng join...intothực sự được dịch để GroupJointrả về các nhóm như new{parent,IEnumerable<child>}vậy, vì vậy bạn chỉ cần gọi Count()vào nhóm:

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

Trong Extension Method cú pháp một join intolà tương đương với GroupJoin(trong khi một joinmà không có một intoJoin):

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

8

Mặc dù ý tưởng đằng sau cú pháp LINQ là mô phỏng cú pháp SQL, bạn không nên luôn nghĩ đến việc dịch trực tiếp mã SQL của mình sang LINQ. Trong trường hợp cụ thể này, chúng tôi không cần phải tham gia nhómtham gia vào là một nhóm tham gia.

Đây là giải pháp của tôi:

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

Không giống như hầu hết là bình chọn giải pháp ở đây, chúng ta không cần j1 , j2 và kiểm tra null trong Count (t => t.ChildId! = 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) })
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.