2009-04-23 9 views
9

Używam metod rozszerzających .Skip() i .Take() z LINQ To SQL od dłuższego czasu bez żadnych problemów, ale we wszystkich sytuacjach, w których je używałem, zawsze był jeden stół - takie jak:LINQ do SQL Paging

database.Users.Select(c => c).Skip(10).Take(10); 

Moim problemem jest to, że jestem teraz wystające komplet wyników z wielu tabel i chcę strony na ogólny zestaw (i nadal uzyskać korzyści z stronicowania w DB) .

Mój model podmiot wygląda następująco:

kampania [ma wiele] Grupy, grupa [ma wiele] kontaktów

ten jest modelowany za pomocą relacji w bazie danych jak

Kampania -> CampaignToGroupMapping -> Grupa -> GroupToContactMapping -> Kontakt

Potrzebuję wygenerować strukturę danych lding szczegóły kampanii i również listę każdego kontaktu związanego z kampanią przez CampaignToGroupMapping, tj

Campaign 
    CampaignName 
    CampaignFrom 
    CampaignDate 
    Recipients 
     Recipient 1 
     Recipient 2 
     Recipient n... 

próbowałem napisać kwerendę za pomocą LINQ .SelectMany do projektu zbiór kontaktów z każdej grupy do jeden zestaw danych liniowych, w nadziei, że mógłbym .Skip() .Take() z tego.

Moja próba była:

var schedule = (from c in database.Campaigns 
       where c.ID == highestPriority.CampaignID 
       select new PieceOfCampaignSchedule 
       { 
        ID = c.ID, 
        UserID = c.UserID, 
        Name = c.Name, 
        Recipients = c.CampaignGroupsMappings.SelectMany(d => d.ContactGroup.ContactGroupMappings.Select(e => new ContactData() { /*Contact Data*/ }).Skip(c.TotalSent).Take(totalRequired)).ToList() 

       }).SingleOrDefault(); 

Problemem jest to, że stronicowania (w odniesieniu do Skip() i Take()) dzieje się dla każdej grupy, a nie całego zestawu danych.

Oznacza to, że jeśli użyję wartości 200 dla parametru totalRequired (przekazywany do .Take()) i mam 3 grupy powiązane z tą kampanią, to zajmie to 200 z każdej grupy - nie 200 z łącznej ilości danych z każdej grupy powiązanej z kampanią.

W SQL, można to osiągnąć z zapytaniem, takie jak:

select * from 
(
    select [t1].EmailAddress, ROW_NUMBER() over(order by CampaignID desc) as [RowNumber] from contacts as [t1] 
    inner join contactgroupmapping as [t2] on [t1].ID = [t2].ContactID 
    inner join campaigngroupsmapping as [t3] on [t3].ContactGroupID = [t2].GroupID 
    where [t3].CampaignID = @HighestPriorityCampaignID 

) as [Results] where [Results].[RowNumber] between 500 and 3000 

Z tego zapytania, ja przywoławczą w połączeniu zespołu styków z każdej grupy związanej z danym kampanii. Moje pytanie brzmi: jak mogę to osiągnąć, używając zamiast tego składni LINQ To SQL?

Odpowiedz

0

Użyj widoku do agregacji wyników z wielu tabel, a następnie użyć LINQ nad widzenia

+0

Idealnie szukałem rozwiązania wykorzystującego LINQ do SQL.Jak wspomniałem w mojej odpowiedzi, mogłem po prostu wykonać zapytanie SQL bezpośrednio z ADO.NET też - ale chciałem użyć LINQ To SQL dla spójności z innym kodem.Dzięki za sugestię – Martin

+1

LINQ do SQL obsługuje widoki.Po prostu przeciągnij i upuść je do projektanta.Zrozumiałem, że chcesz LINQ do rozwiązania SQL.Zadziałem ci stworzyć widok do użycia przez LINQ do architektury SQL – rguerreiro

4

naśladować zapytanie SQL podany byłoby to zrobić:

var schedule = (from t1 in contacts 
       join t2 in contactgroupmapping on t1.ID equals t2.GroupID 
       join t3 in campaigngroupsmapping on t3.ContactGroupID = t2.GroupID 
       where t3.CampaignID = highestPriority.CampaignID 
       select new PieceOfCampaignSchedule 
       { 
        Email = t1.EmailAddress 
       }).Skip(500).Take(2500).ToList() 

Próbujesz stronie nad kampaniami, odbiorcami lub oboma?

+0

Uważam, że musisz zamówić przed użyciem Skip and Take. Tak mi się udało. –

0

Myślę, że twoja próba jest naprawdę bliska; Może ja czegoś brakuje, ale myślę, że po prostu trzeba zamknąć SelectMany() przed SKIP/Take:

Recipients = c.CampaignGroupsMappings.SelectMany(d => d.ContactGroup.ContactGroupMappings.Select(e => new ContactData() { /*Contact Data*/ })).Skip(c.TotalSent).Take(totalRequired).ToList() 

Uwaga: dodano ")" po "/ * Dane kontaktowe * /})" i usunięto ")" z po ".Take (totalRequired) "