我在生产环境中遇到了扩展问题。少量记录处理良好。但体积越大,花费的时间就越长。这些课程只是为了说明这一点。
Party {
DateTime When { get; set; }
ICollection<Attendee> Attendees { get; set; }
}
Attendee {
ICollection<Gift> Gifts { get; set; }
ICollection<Allergy> Allergies { get; set; }
}
IEnumerable<Party> GetAllPartiesByDate(DateTime date) {
var parties = Context.Parties
.Include(p => p.Attendees).ThenInclude(a => a.Gifts)
.Include(p => p.Attendees).ThenInclude(a => a.Allergies)
.Where(p.When == date)
.ToList();
return parties;
}
有 4 个匹配派对,每个派对有 7 名参加者,每个参加者有 3 件礼物和 2 种过敏 数据库中有 172 行,分布在 6 个表中
4 + (4*7) + (4*7*3) + (4*7*2)
EF 通过单个 SQL 查询返回 168 行,还不错。
4 * (7) * (3) * (2)
但是将每个值放大 10 倍,您将在数据库中获得 142,840 行
40 + (40*70) + (40*70*30) + (40*70*20)
但是,单个 EF 查询的结果集会在每个连续的一对多关系上爆炸,并且 tries 返回 40 * 70 * 30 * 20
1,680,000 行
当使用更现代版本的 Entity Framework Core 时,笛卡尔爆炸的解决方案是使用 AsSplitQuery
由于不幸的技术原因,我们无法更新 Entity Framework Core 3.1 以后的版本。
但是如何在 EF Core 3.1 中实现 AsSplitQuery?
解决方案是依赖 EF Core 上下文更改跟踪行为。 IE。在给定上下文中的后续加载中,EF 检查您是否已经拥有实体的实例,如果有则更新其内容。
更改跟踪必须开启才能正常工作。
IQueryable<Party>
IEnumerable<Party> GetAllPartiesByDate(DateTime date) {
//Keep the search condition.
IQueryable<Party> partyQuery = Context.Parties.Where(p.When == date);
//Triger an SQL call with ToList, this creates instances of Party.
List<Party> parties = partyQuery.ToList();
//Trigger a sperate SQL call including specific related data.
//This updates the already loaded Party instances.
List<Party> loadGifts = partyQuery.Include(p => p.Attendees).ThenInclude(a => a.Gifts).ToList();
//Repeat
List<Party> loadAllergies = partyQuery.Include(p => p.Attendees).ThenInclude(a => a.Allergies).ToList();
return parties;
}