[英]How to explicitly load relations for multiple models at once in Entity Framework?
I have a model similar to the following: 我有一个类似于以下的模型:
class Parent {
public int Id { get; set; }
public string Name { get;set; }
public ICollection<Child> Children { get; set; }
public GrandChildren SpecialGrandChild {
get {
return Children.SelectMany(c => c.Children).Where(...).Single();
}
}
}
class Child {
public int Id { get; set; }
public int ParentId { get; set; }
public Parent Parent { get; set; }
public ICollection<GrandChild> Children { get; set; }
}
class GrandChild {
public int Id { get; set; }
public string Name { get;set; }
public int ParentId { get; set; }
public Child Parent { get; set; }
}
I also have a fairly complex query involving all three tables. 我也有一个涉及所有三个表的相当复杂的查询。 From that query I want to extract all the Parent
objects, and I will be displaying a property of the SpecialGrandChild
for each one. 从该查询中,我想提取所有Parent
对象,并且我将为每个对象显示SpecialGrandChild
的属性。
The problem is that if I do: 问题是,如果我这样做:
query.Include(p => p.Children.Select(c => c.Children));
EF will generate an ungodly sql query, and take a ton of time to build the query (on some cases over 10 seconds!). EF会生成一个不友好的sql查询,并花费大量时间来构建查询(在某些情况下会超过10秒!)。 The query is cached so further calls are much faster. 查询被缓存,因此进一步的调用要快得多。 If I drop the Include
call, I do not get such a bad first-call performance, but of course I get a worse performance as I will be doing M*N+1
queries (for each Parent, fetch the Children, and for each Child fetch the GrandChildren). 如果放弃Include
调用,我不会获得如此差的首次调用性能,但是当然,我会得到更差的性能,因为我将执行M*N+1
查询(对于每个父级,获取子级以及每个孩子拿来GrandChildren)。
So the question is: can I explicitly load all the Children and GrandChildren for all the loaded Parents in a single call? 所以问题是:我可以在一次调用中为所有已加载的“父母”显式加载所有“子级”和“孙子级”吗? If so, how can I do so? 如果是这样,我该怎么办?
I tried querying all the Childs for the currently loaded Parents as follows: 我尝试查询所有Childs以获取当前加载的Parents,如下所示:
var ids = parents.Select(p => p.Id);
(from c in Childs where ids.Contains(c.ParentId) select c).Include("Children").Load();
But that call does not tell EF that all the associated Childs are loaded so it still goes to the DB when I access the association properties. 但是,该调用不会告诉EF所有关联的子级都已加载,因此当我访问关联属性时,它仍将转到DB。
Load your data in two steps: 分两步加载数据:
var dbParent = ...; // query all Parent's
var dbChild = ...; // query all Child's
var parents = dbParent.Include(p => p.Children).ToList();
dbChild.Include(p => p.Children).toList();
That should make parents have a list of all parents, and because of tracking, each parent will have each of its children. 这应该使父母拥有所有父母的列表,并且由于跟踪,每个父母将拥有其每个孩子。
If you have to apply a filter condition on parent, you should make it on children too. 如果必须对父母应用过滤条件,则也应对孩子应用过滤条件。
Since I don't know enough about your parent variable and a context your parent objects are probably attached on (or maybe not) I can't give you a precise answer. 由于我对您的父变量和上下文不了解,您的父对象可能附加在(或可能不附加)了,所以我无法给您一个确切的答案。 But what you're looking for should look like this where ctx is an instance of your context and Parents a DbSet Property: 但是您要查找的内容应如下所示,其中ctx是上下文的实例,而Parents是DbSet属性:
IQueryable<Parent> query = ctx.Parents.Include("Children.Children");
List<Parent> myTree = query.toList();
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.