实现包含子类的 ICollection 结构 [英] Materializing an ICollection structure containing subclasses
问题描述
我正在审查一些在 EF 4 天内编写的代码,因为它在性能基准测试中脱颖而出.
I'm reviewing some code that was written in the EF 4 days because it stands out during performance benchmarking.
代码的目的是使用实体框架实现 ICollection
(我们现在使用的是 EF 6.1).
The purpose of the code is to materialize an ICollection<MyBaseClass>
using Entity Framework (we're now on EF 6.1).
代码存在是因为特定子类中存在的引用在检索时没有具体化
The code exists because references present in specific subclasses aren't materialized when retrieving
public Parent
{
public virtual ICollection<MyBaseClass>() Base { get; set; }
}
来自数据库,当实际存储的类型是 MyBaseClass 的子类时.
from the database, when the actual types stored are subclasses of MyBaseClass.
示例子类:
public SubA : MyBaseClass
{
public virtual ICollection<Options> Ref1 { get; set; }
}
目前,代码执行如下操作:
Currently, the code does something like this:
var parent = ctx.Parents.Include(p => p.Base).Where(...).Single();
LoadSubclasses(parent.Base);
...
private void LoadSubclasses(IEnumerable<MyBaseClass> myBase)
{
foreach (var my in myBase)
{
if (my is SubA)
{
this.Entry(my).Reference("Ref1").Load();
this.Entry((SubA)my).Ref1).Collection("Options").Load();
}
else... // Similar for other subclasses
}
}
请注意,ICollection
包含多个具体子类的混合.ICollection
中一般有几百个对象.
Note that ICollection<MyBaseClass>() Base
contains a mix of several concrete subclasses. There are generally a few hundred objects in the ICollection
.
有没有更有效的方式实现Base
?
Is there a more efficient way to materialize Base
?
推荐答案
不能提前说性能是否会更好(有时执行单个复杂查询,尤其是子集合包含实际上可能会产生负面影响),但是您可以将数据库查询的数量减少到 K,其中 K 是需要额外包含的子类类型的数量.
It cannot be said in advance if the performance will be better (sometimes executing a single complex query, especially with sub collection includes may have actually negative impact), but you can minimize the number of database queries to K, where K is the number of subclass types that need additional includes.
您需要将 LoadSubclasses
方法基于表示所有基本实体的 IQueryable
方法,并使用 OfType
过滤器:
You need to base the LoadSubclasses
method on IQueryable<TBase>
representing all base entities, and execute one query per each subclass type using OfType
filter:
private void LoadSubclasses(IQueryable<MyBaseClass> baseQuery)
{
// SubA
baseQuery.OfType<SubA>()
.Include(x => x.Ref1.Options)
.Load();
// Similar for other subclasses
}
您的示例的用法是:
var parent = ctx.Parents.Include(p => p.Base).Where(...).Single();
LoadSubclasses(ctx.Entry(parent).Collection(p => p.Base).Query());
或更笼统地说:
var parentQuery = ctx.Parents.Where(...);
var parents = parentQuery.Include(p => p.Base).ToList();
LoadSubclasses(parentQuery.SelectMany(p => p.Base));
这篇关于实现包含子类的 ICollection 结构的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!