实现包含子类的ICollection结构

问题描述 投票:0回答:2

我正在审查一些在EF 4天内编写的代码,因为它在性能基准测试期间脱颖而出。

代码的目的是使用Entity Framework实现ICollection<MyBaseClass>(我们现在使用的是EF 6.1)。

代码存在,因为在检索时未实现特定子类中存在的引用

public Parent
{
    public virtual ICollection<MyBaseClass>() Base { get; set; }
}

从数据库中,当存储的实际类型是MyBaseClass的子类时。

示例子类:

public SubA : MyBaseClass
{
    public virtual ICollection<Options> Ref1 { get; set; }
}

目前,代码执行如下操作:

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<MyBaseClass>() Base包含几个具体子类的混合。在ICollection中通常有几百个物体。

有没有更有效的方法来实现Base

entity-framework entity-framework-6
2个回答
3
投票

如果性能会更好(有时执行单个复杂查询,尤其是子集合包含可能实际上会产生负面影响),则不能提前说出来,但是您可以将数据库查询的数量最小化到K,其中K是数量需要额外包含的子类类型。

您需要在代表所有基本实体的LoadSubclasses上建立IQueryable<TBase>方法,并使用OfType过滤器对每个子类类型执行一个查询:

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));

0
投票

对于EF Core 2.1或更高版本的用户,这个功能is now supported开箱即用。

2010年的要求:

当在实体框架的数据模型中具有导航属性时,除了使用OfType <>或者通过导航属性急切加载派生类型本身时,它还不具有加载该导航属性的能力。

回复2018年:

该功能是EF Core 2.1的一部分,目前正在预览中。如果您发现任何问题,请在我们的问题跟踪器中创建问题。

© www.soinside.com 2019 - 2024. All rights reserved.