LINQ To SQL 分页

9

我一直在使用LINQ To SQL的.Skip()和.Take()扩展方法,处理单个表格的数据,这段时间以来一直没有遇到问题。例如:

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

我的问题是,我现在从多个表中投影一组结果,并且希望在整体集合上进行分页(仍然能够从数据库中获得分页的好处)。
我的实体模型如下:
一个活动[拥有多个]群组,一个群组[拥有多个]联系人
这通过数据库中的关系建模,如下所示:
活动-> 活动到群组映射-> 群组 -> 群组到联系人映射-> 联系人
我需要生成一个数据结构,保存活动的详细信息以及通过活动到群组映射与活动相关联的每个联系人的列表。
Campaign
   CampaignName
   CampaignFrom
   CampaignDate
   Recipients
      Recipient 1
      Recipient 2
      Recipient n...

我曾尝试使用.SelectMany编写LINQ查询,将每个组的联系人集合投影到一个线性数据集中,希望能从中使用.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())是针对每个分组而不是整个数据集进行的。
这意味着,如果我将参数totalRequired(传递给.Take())的值设为200,并且与此广告系列相关联的有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
为了模仿您提供的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()

你是想对活动、收件人,还是两者都进行分页?

我认为在使用Skip和Take之前需要进行排序。对我来说就是这样。 - Eduardo Xavier

0

我认为你的尝试非常接近;也许我漏掉了什么,但我认为你只需要在Skip/Take之前关闭SelectMany():

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

注意:在“/* 联系数据 */ })”后添加“)”并从“.Take(totalRequired)”后删除“)”

0
使用视图来聚合多个表的结果,然后在视图上使用LINQ。

理想情况下,我希望只使用LINQ To SQL来解决问题。就像我在答案中提到的那样,我也可以直接从ADO.NET执行SQL查询,但是为了与其他代码保持一致,我想使用LINQ To SQL。感谢您的建议。 - Martin
1
LINQ to SQL 支持视图。只需将它们拖放到设计器中即可。我理解您想要一个 LINQ to SQL 的解决方案。我建议您创建一个视图供 LINQ to SQL 框架使用。 - rguerreiro

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接