LINQ To SQL Paging - PullRequest
       11

LINQ To SQL Paging

9 голосов
/ 23 апреля 2009

Я уже некоторое время без проблем использую методы расширения .Skip () и .Take () с LINQ To SQL, но во всех ситуациях, в которых я их использовал, всегда было для одной таблицы - такие как:

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

Моя проблема заключается в том, что я теперь проецирую набор результатов из нескольких таблиц и хочу просмотреть весь набор (и при этом получить выгоду от разбивки на страницы в БД).

Моя модель сущности выглядит так:

Кампания [имеет много] групп, группа [имеет много] контактов

это моделируется через отношения в базе данных, такие как

Кампания -> CampaignToGroupMapping -> Группа -> GroupToContactMapping -> Контакт

Мне нужно сгенерировать структуру данных, содержащую подробности кампании, а также список каждого контакта, связанного с кампанией через CampaignToGroupMapping, т.е.

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

Я пытался написать запрос LINQ, используя .SelectMany для проецирования набора контактов из каждой группы в один линейный набор данных, в надежде, что смогу .Skip () .Take () из этого.

Моя попытка была:

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

Проблема в том, что подкачка (в отношении Skip () и Take ()) происходит для каждой группы, а не для всего набора данных.

Это означает, что если я использую значение 200 для параметра totalRequired (передано в .Take ()) и у меня есть 3 группы, связанные с этой кампанией, то для каждой группы потребуется 200, а не 200 общие данные из каждой группы, связанной с кампанией.

В SQL я мог бы достичь этого с помощью запроса:

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

С помощью этого запроса я пролистываю объединенный набор контактов из каждой группы, связанной с конкретной кампанией. Поэтому мой вопрос: как я могу добиться этого, используя вместо этого синтаксис LINQ To SQL?

Ответы [ 3 ]

4 голосов
/ 23 апреля 2009

Чтобы имитировать предоставленный вами SQL-запрос, вы должны сделать следующее:

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

Пытаетесь ли вы пролистать кампании, получателей или оба?

0 голосов
/ 23 апреля 2009

Я думаю, что ваша попытка действительно близка; Может быть, я что-то упустил, но я думаю, что вам просто нужно закрыть свой SelectMany () перед Skip / Take:

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

Примечание: добавлено ")" после "/ * Контактные данные * /})" и удалено ")" после ".Take (totalRequired)"

0 голосов
/ 23 апреля 2009

Используйте представление для агрегирования результатов из нескольких таблиц, а затем используйте LINQ поверх представления

...