EF Eager获取派生类

Hen*_*rik 7 c# entity-framework entity-framework-6

我正在使用EF6并试图获取对象的整个结构.问题是我正在使用继承.

我们说我有这个课程.

的DbContext

DbSet<A> A { get; set; }
Run Code Online (Sandbox Code Playgroud)

示例类

public class A
{
    public string Id { get; set; }
    public IList<Base> Bases { get; set; }
}

public abstract class Base
{
    public int Id { get; set; }
    public string Name { get; set; }
}

public abstract class Base1 : Base
{
    public SomeClass SomeClass { get; set; }
}

public class Base2 : Base1
{

}

public class Base3 : Base1
{
    public SomeOtherClass SomeOtherClass { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我得到的错误是:

The Include path expression must refer to a navigation property defined on the type. 
Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Run Code Online (Sandbox Code Playgroud)

为什么它不适用于以下情况?

    public IEnumerable<A> GetAll(string id)
    {

        return _ctx.A
               .Include(x => x.Bases.OfType<Base1>().Select(y=>y.SomeClass))
               .Where(x => x.Id.Equals(id)).ToList();
    }
Run Code Online (Sandbox Code Playgroud)

新的例子

public IEnumerable<A> GetAll(string id)
{

   var lists = _dbContext.A.Where(x => x.Id == id);
   lists.SelectMany(a => a.Bases).OfType<Base1>().Include(e=>e.SomeClass).Load();
   lists.SelectMany(b => b.Bases).OfType<Base3>().Include(e => e.SomeOtherClass).Load();

   return lists;
}
Run Code Online (Sandbox Code Playgroud)

编辑:添加了一个似乎有效的新示例.

Iva*_*oev 2

很快,就不可能开箱即用了。

我可以建议的唯一解决方法是具体化主查询结果,然后使用与主查询相同的过滤器执行OfType必要的多个查询Includes,并依赖 EF 导航属性修复。

它需要类中的反向导航属性Base

public abstract class Base
{
   // ...
   public A A { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以使用这样的东西:

public IEnumerable<A> GetAll(string id)
{
    var a = _ctx.A.Where(x => x.Id == id).ToList();
    _ctx.Base.OfType<Base1>().Include(e => e.SomeClass).Where(e => e.A.Id == id).Load();
    _ctx.Base.OfType<Base3>().Include(e => e.SomeOtherClass).Where(e => e.A.Id == id).Load();
    return a;
}
Run Code Online (Sandbox Code Playgroud)

可以在不使用反向导航属性的情况下使用相同的想法,但使用返回的基本 Id 作为过滤器:

public IEnumerable<A> GetAll(string id)
{
    var a = _ctx.A.Include(e => e.Bases)
        .Where(x => x.Id == id).ToList();

    var baseIds = a.SelectMany(e => e.Bases.OfType<ModelA.Base1>().Select(b => b.Id));
    db.Base.OfType<Base1>().Include(e => e.SomeClass)
        .Where(e => baseIds.Contains(e.Id)).Load();

    baseIds = a.SelectMany(e => e.Bases.OfType<Base3>().Select(b => b.Id));
    db.Base.OfType<Base3>().Include(e => e.SomeOtherClass)
        .Where(e => baseIds.Contains(e.Id)).Load();

    return a;
}
Run Code Online (Sandbox Code Playgroud)