LINQ - Sola Katılma, Gruplama ve Sayma


166

Diyelim ki bu SQL var:

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

Bunu nasıl LINQ SQL'e çevirebilirim? COUNT (c.ChildId) sıkışmış var, oluşturulan SQL her zaman COUNT (*) çıktı gibi görünüyor. Şimdiye kadar aldığım şey:

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

Teşekkür ederim!

Yanıtlar:


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

Tamam, işe yarıyor, ama neden? Nasıl düşünüyorsun? Boş değerlerin sayılması bize COUNT (c.ChildId) ile aynı şeyi nasıl vermez? Teşekkürler.
pbz

4
SQL böyle çalışır. COUNT (alan adı), bu alandaki boş olmayan satırları sayar. Belki sorunuzu almıyorum, lütfen durumun bu olup olmadığını açıklayın.
Mehrdad Afshari

Sanırım bunu her zaman satır sayma açısından düşündüm, ama haklısın, sadece boş olmayan değerler sayılır. Teşekkürler.
pbz

1
.Count (), bu gruptaki tüm satırları bu arada sayacak olan COUNT (*) oluşturur.
Mehrdad Afshari

Aynı sorunu yaşadım ancak t => t.ChildID! = Null karşılaştırması benim için çalışmadı. Sonuç her zaman boş bir nesneydi ve Resharper ifadenin her zaman doğru olduğundan şikayet etti. Bu yüzden kullandım (t => t! = Null) ve bu benim için çalıştı.
Joe

55

Bir alt sorgu kullanmayı düşünün:

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

Sorgu türleri bir ilişkilendirmeyle bağlıysa, bu basitleşir:

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

Doğru hatırlıyorsam (bir süredir), bu sorgu büyük bir basitleştirilmiş bir versiyonuydu. Eğer ihtiyacım olan tek şey anahtar ve saymak çözüm daha temiz / daha iyi olurdu.
pbz

1
Yorumunuz, orijinal soru ve yükseltilmiş cevaplar bağlamında anlamsızdır. Ek olarak - anahtardan daha fazlasını istiyorsanız, çizmek için üst satırın tamamına sahipsiniz.
Amy B

letAnahtar kelime içeren çözüm, @Mosh grubuna katılmış çözümle aynı bir alt sorgu oluşturur.
Mohsen Afshin

@MohsenAfshin evet, doğrudan üstündeki cevabımda bir alt sorgu ile sorgu ile aynı bir alt sorgu oluşturur.
Amy B

39

GEÇ CEVAP:

Yaptığınız tek şey Count () ise sol birleşmeye hiç ihtiyacınız yok . join...intoAslında GroupJoinhangi gruplamaların döndürdüğüne çevirildiğini unutmayın, new{parent,IEnumerable<child>}bu nedenle Count()grubu aramanız yeterlidir :

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

Uzantı Yöntemi'nde sözdizimi a join intoeşittir GroupJoin( joinbir intois olmadan a 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 sözdiziminin arkasındaki fikir SQL sözdizimini taklit etmek olsa da, her zaman SQL kodunuzu doğrudan LINQ'ya çevirmeyi düşünmemelisiniz. Bu özel durumda, gruba katılmamıza gerek yoktur çünkü katılmak grubun kendisinin birleşmesidir.

İşte benim çözümüm:

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

Burada en çok oylanan çözümün aksine, Count'da j1 , j2 ve null kontrolüne ihtiyacımız yok (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) })
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.