我已经在 LINQ To SQL 中使用 .Skip() 和 .Take() 扩展方法有一段时间了,没有任何问题,但在我使用它们的所有情况下,它始终适用于单个表 - 例如:
database.Users.Select(c => c).Skip(10).Take(10);
我的问题是,我现在正在投影来自多个表的一组结果,并且我想对整个结果集进行分页(并且仍然获得在数据库分页的好处)。
我的实体模型如下所示:
一个活动[有很多]群组,一个群组[有很多]联系人
这是通过数据库中的关系建模的,例如
营销活动 -> 营销活动到组映射 -> 组 -> 组到联系人映射 -> 联系人
我需要生成一个数据结构,其中包含活动的详细信息以及通过 CampaignToGroupMapping 与活动关联的每个联系人的列表,即
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 使用值 200(传递给 .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 语法来实现这一目标?
要模仿您提供的 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()
您是否正在尝试翻页活动、收件人或两者?
使用视图聚合多个表的结果,然后在视图上使用 LINQ
我认为你的尝试非常接近;也许我错过了一些东西,但我认为你只需要在 Skip/Take 之前关闭 SelectMany() 即可:
Recipients = c.CampaignGroupsMappings.SelectMany(d => d.ContactGroup.ContactGroupMappings.Select(e => new ContactData() { /*Contact Data*/ })).Skip(c.TotalSent).Take(totalRequired).ToList()
注意:在“/* Contact Data */ })”之后添加了“)”,并从“.Take(totalRequired)”之后删除了“)”