EF预先获取派生类

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

我们说我有这个课程。

的DbContext

DbSet<A> A { get; set; }

示例类

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

我得到的错误是:

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.

为什么它不适用于以下内容?

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

新的例子

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

编辑:增加了一个新的例子,似乎工作。


不久之后,它就不可能出现。

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

它需要在Base类中具有逆向导航属性:

public abstract class Base
{
   // ...
   public A A { get; set; }
}

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

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

同样的想法可以使用没有逆向导航属性,但使用返回的基础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;
}

你的问题不在Select(y=>y.SomeClass)它自身,如果你试图从你的查询中删除它并再次执行你的查询,你会得到同样的问题。 您不能将继承的类型作为子类来查询,并且您期望从实体框架中处理所有事情。

如果你看看你的数据库,表格Base有一个对A的引用,它是从A到Base的关系1-许多。

您可以通过在类Base添加导航属性A ,并在添加DbSet<Base> Bases{get;set;} A.Id = something获取所有Base实体,其中A.Id = something ,然后您的查询将如下所示

var details = _ctx.Bases.OfType<Base1>()
                        .Include(t=>t.Box)
                        .Include(t=>t.SomeClass)
                        .Where(t=>t.Box.Id ==something);

其他选项,使用DTO,在下面的示例中我使用了Anonymous类型,但您可以创建一个强大的DTO类型以满足您的要求。

var details  = _ctx.A
                   .Where (t=>t.Id ==something)
                   .Select(a => new {
                        Id = a.Id,
                        // ... other A properites , 
                        Bases = _ctx.Bases.OfType<Base1>().Select(m=> new {
                            Id = m.Id,
                            Name = m.Name,
                            SomeClass = m.SomeClass
                        });
                   }

希望对你有帮助

链接地址: http://www.djcxy.com/p/36301.html

上一篇: EF Eager fetching derived class

下一篇: Web User Controls in different Project