[英]How to avoid “select n+1” pattern in Linq
我有以下形式的查询(包括LinqKit):
Expression<Func<Country, DateTime, bool>> countryIndepBeforeExpr =
(ct, dt) => ct.IndependenceDate <= dt;
DateTime someDate = GetSomeDate();
var q = db.Continent.AsExpandable().Select(c =>
new
{
c.ID,
c.Name,
c.Area,
Countries = c.Countries.AsQueryable()
.Where(ct => countryIndepBeforeExpr.Invoke(ct, someDate))
.Select(ct => new {ct.ID, ct.Name, ct.IndependenceDate})
});
现在我想通过迭代q
...但由于Countries
的每个元素的属性的类型的IQueryable
,这将是懒加载,导致被执行N + 1个查询,这是不是很好。
编写此查询以便所有必要的数据将在单个查询中提取到db的正确方法是什么?
编辑
嗯,如果我在问这个问题之前实际运行了Sql跟踪,那可能会有所帮助。 我以为 ,因为内财产是类型的IQueryable
,这将是懒加载...但是做了一些实际测试后,事实证明,LINQ到实体是足够聪明的同时运行整个查询。
很抱歉浪费您的全部时间。 我将删除该问题,但是由于它已经有了答案,所以不能。 也许可以作为对他人的某种警告,在假设它成立之前对您的假设进行检验 !
呼叫大洲时,将国家/地区包括在模型中。 用这样的东西:
var continents = db.Continent.Include(c => c.Countries).ToArray();
然后,您可以在没有iQueryable对象的情况下进行linq操作。
我认为这应该工作(将AsExpandable()
移到IQueryable
根目录):
var q = db.Continent
.AsExpandable()
.Select(c => new
{
c.ID,
c.Name,
c.Area,
Countries = c.Countries
.Where(ct => countryIndepBeforeExpr.Invoke(ct, someDate))
.Select(ct => new {ct.ID, ct.Name, ct.IndependenceDate})
});
如果没有,请创建两个IQueryable
并将它们连接在一起:
var continents = db.Continents;
var countries = db.Countries
.AsExpandable()
.Where(c => countryIndepBeforeExpr.Invoke(c, someDate))
.Select(c => new { c.ID, c.Name, c.IndependenceDate });
var q = continents.GroupJoin(countries,
continent => continent.ID,
country => country.ContinentId,
(continent, countries) => new
{
continent.ID,
continent.Name,
continent.Area,
Countries = countries.Select(c => new
{
c.ID,
c.Name,
c.IndependenceDate
})
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.