2012-03-06 24 views
14

Nie mogę rozwiązać tego problemu za pomocą kwerendy LINQ.Zagnieżdżona grupa według LINQ

Mamy więc strukturę tabeli w następujący sposób: Id || bug_category || bug_name || bug_details || bug_priority

Najpierw chcę pogrupować według bug_category. Dla każdej bug_category, chcę z kolei grupować według bug__priority.

Więc zasadniczo chcę coś takiego:

bug_category = Dźwięk :: Nie błędów -> Critical = 3, medium = 2 i niski = 7 błędów.
bug_category = VIDEO :: Liczba błędów -> Krytyczny = 5, Średni = 1 i Niski = 9 błędów.

Poniższa kwerenda zwraca wszystkie unikalne kombinacje kategorii i customer_priority:

(gdzie RawDataList to po prostu lista danych, które ma wspomnianą wyżej strukturę)

 var ProceesedData = from d in RawDataList 
         group d by new { d.bug_category, d.bug_priority } into g 
         select new 
         { 
          g.Key.bug_category, 
          g.Key.bug_priority 
         }; 

Poniższa kwerenda zwraca kategoria, po której następuje lista rekordów w tej kategorii:

  var ProceesedData = from d in RawDataList 
         group d by d.bug_category into g 
         select new { g.Key, records = g 
         }; 

Ale ja jestem można kontynuować, ponieważ ProcessedData (zmienna zwracana) jest nieznanym typem. Jakieś przemyślenia na ten temat?

Odpowiedz

25

Podejrzewam chcesz (imiona zmienione na bardziej idiomatyczne):

var query = from bug in RawListData 
      group bug by new { bug.Category, bug.Priority } into grouped 
      select new { 
       Category = grouped.Key.Category, 
       Priority = grouped.Key.Priority, 
       Count = grouped.Count() 
      }; 

Następnie:

foreach (var result in query) 
{ 
    Console.WriteLine("{0} - {1} - {2}", 
         result.Category, result.Priority, result.Count); 
} 

Alternatywnie (ale patrz niżej):

var query = from bug in RawListData 
      group bug by new bug.Category into grouped 
      select new { 
       Category = grouped.Category, 
       Counts = from bug in grouped 
         group bug by grouped.Priority into g2 
         select new { Priority = g2.Key, Count = g2.Count() } 
      }; 

foreach (var result in query) 
{ 
    Console.WriteLine("{0}: ", result.Category); 
    foreach (var subresult in result.Counts) 
    { 
     Console.WriteLine(" {0}: {1}", subresult.Priority, subresult.Count); 
    } 
} 

EDIT: Jak odnotowane w komentarzach, spowoduje to wiele zapytań SQL. Aby uzyskać podobną strukturę wynik, ale bardziej efektywnie można użyć:

var dbQuery = from bug in RawListData 
       group bug by new { bug.Category, bug.Priority } into grouped 
       select new { 
        Category = grouped.Key.Category, 
        Priority = grouped.Key.Priority, 
        Count = grouped.Count() 
       }; 

var query = dbQuery.ToLookup(result => result.Category, 
          result => new { result.Priority, result.Count }; 


foreach (var result in query) 
{ 
    Console.WriteLine("{0}: ", result.Key); 
    foreach (var subresult in result) 
    { 
     Console.WriteLine(" {0}: {1}", subresult.Priority, subresult.Count); 
    } 
} 
+2

Drugie zapytanie stworzy dla każdej grupy kwerendy wtórne, więc myślę, że lepszym rozwiązaniem jest pierwsza, a następnie ToLookup według kategorii –

+0

@AdrianIftode: Wypróbowałeś to? Nie, ale oczekiwałbym * odpowiedniego kodu SQL, który zostałby wygenerowany, aby zrobić to wszystko za jednym razem. –

+0

Tak, z LinqPad, jedno zapytanie dla grup kategorii i innych zapytań X dla grup priorytetów –

5

myślę szukasz czegoś takiego:

var processedData = 
     rawData.GroupBy(bugs => bugs.bug_category, 
      (category, elements) => 
      new 
       { 
        Category = category, 
        Bugs = elements.GroupBy(bugs => bugs.bug_priority, 
             (priority, realbugs) => 
             new 
              { 
               Priority = priority, 
               Count = realbugs.Count() 
              }) 
       }); 
    foreach (var data in processedData) 
    { 
     Console.WriteLine(data.Category); 

     foreach (var element in data.Bugs) 
      Console.WriteLine(" " + element.Priority + " = " + element.Count); 
    } 
+0

Dziękujemy za dostarczenie rozwiązania. Doceniam to ! – Nandu

+0

@Nandu: Zdajesz sobie sprawę, że jest to zasadniczo to samo, co moje drugie zapytanie, tylko w formularzu wyrażenia lambda, prawda? Zauważ, że ma taką samą słabą wydajność (jak to jest to samo zapytanie), które zauważył Adrian. –

+2

Niebezpieczeństwo przyjęcia 9 minut więcej niż Jon Skeet, aby napisać odpowiedź;) –

12

Jest łatwiejszy sposób, aby osiągnąć ugrupowania zagnieżdżonych. Przetestowałem to w kolekcjach pamięci, niezależnie od tego, czy dany dostawca DB dobrze sobie z nim poradzi, czy też nie, lub czy dobrze działa, jest nieznany.

Zakładając, że miał dwie właściwości i chciał grupy zarówno przez państwa i kraj:

var grouped = People 
    .GroupBy(l => new { l.State, l.Country})//group by two things 
    .GroupBy(l=> l.Key.Country)//this will become the outer grouping 


foreach(var country in grouped) 
{ 
    foreach(var state in country) 
    { 
    foreach(var personInState in state) 
    { 
     string description = $"Name: {personInState.Name}, State: {state.StateCode}, Country: {country.CountryCode}"; 
     ... 

    } 
    } 
} 
+0

To trudna odpowiedź! –

+0

Yeh, zajęło mi trochę czasu, aby dowiedzieć się, kiedy potrzebuję tego dla siebie, a ja w rzeczywistości wracam do mojej odpowiedzi, kiedy muszę to zrobić. – AaronLS