2009-04-23 11 views
9

J'utilise les méthodes d'extension .Skip() et .Take() avec LINQ To SQL depuis un moment maintenant sans aucun problème, mais dans toutes les situations où je les ai utilisées, cela a toujours été pour une seule table - comme:LINQ To SQL Paging

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

Mon problème est que je suis en train de projeter une série de résultats de plusieurs tables et je veux à la page sur l'ensemble global (et encore obtenir le bénéfice de la pagination à la DB) .

Mon modèle d'entité ressemble à ceci:

Une campagne [a beaucoup] groupes, un groupe [a beaucoup] contacts

permet de modéliser une relation dans la base de données comme

Campagne -> CampaignToGroupMapping -> Groupe -> GroupToContactMapping -> Contact

Je dois générer une structure de données lding les détails d'une campagne et une liste de chaque contact associé à la campagne à travers le CampaignToGroupMapping, c.-à-

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

j'avais essayé d'écrire une requête LINQ en utilisant .SelectMany pour projeter l'ensemble des contacts de chaque groupe en un ensemble de données linéaire, dans l'espoir que je pourrais .Skip() .Take() de cela.

Ma tentative a été:

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

Le problème est que la recherche de personnes (en ce qui concerne SKIP() et Take()) se produit pour chaque groupe, et non pas l'ensemble des données.

Cela signifie que si j'utilise la valeur 200 pour le paramètre totalRequired (passé à .Take()) et j'ai 3 groupes associés à cette campagne, il faudra 200 de chaque groupe - et non 200 à partir des données totale de chaque groupe associé à la campagne.

Dans SQL, je pourrais y parvenir avec une requête telle que:

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 

Avec cette requête, je suis la pagination sur l'ensemble combiné de contacts de chaque groupe associé à la campagne particulière. Donc ma question est, comment puis-je y parvenir en utilisant la syntaxe LINQ To SQL à la place?

Répondre

0

Utilisez une vue d'agréger les résultats des multiples tables, puis utiliser LINQ sur la vue

+0

Idéalement, je cherchais une solution utilisant LINQ To SQL uniquement Comme je l'ai mentionné dans ma réponse, je pouvais aussi exécuter la requête SQL directement depuis ADO.NET - mais je voulais utiliser LINQ To SQL SQL pour la cohérence avec les autres codes Merci pour la suggestion – Martin

+1

LINQ to SQL supporte les vues Il suffit de les faire glisser dans le concepteur J'ai compris que vous vouliez une solution LINQ to SQL Je vous ai suggéré de créer une vue à utiliser par le framework LINQ to SQL – rguerreiro

4

Pour imiter la requête SQL que vous avez fourni vous faire:

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

Essayez-vous à la page sur les campagnes, les destinataires ou les deux?

+0

Je crois que vous devez commander avant d'utiliser Skip and Take Travaillé comme ça pour moi. –

0

Je pense que votre tentative est vraiment proche; Peut-être que je manque quelque chose, mais je pense que vous avez juste besoin de fermer votre SelectMany() avant le Saut/Prendre:

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

Note: ajoutée ")" après "/ * données de contact * /})" et enlevé ")" d'après ".Take (totalRequired) "