EF Eager获取派生类
我正在使用EF6并试图获取对象的整个结构。 问题是我正在使用inheritance。
我们说我有这个课程。
的DbContext
DbSet A { get; set; }
示例类
public class A { public string Id { get; set; } public IList 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 GetAll(string id) { return _ctx.A .Include(x => x.Bases.OfType().Select(y=>y.SomeClass)) .Where(x => x.Id.Equals(id)).ToList(); }
新的例子
public IEnumerable GetAll(string id) { var lists = _dbContext.A.Where(x => x.Id == id); lists.SelectMany(a => a.Bases).OfType().Include(e=>e.SomeClass).Load(); lists.SelectMany(b => b.Bases).OfType().Include(e => e.SomeOtherClass).Load(); return lists; }
编辑:添加了一个似乎有效的新示例。
很快,它不可能开箱即用。
我可以建议的唯一解决方法是实现主查询结果,然后使用与主查询相同的filter执行具有必要Includes
多个OfType
查询,并依赖于EF导航属性修正。
它需要Base
类中的反向导航属性:
public abstract class Base { // ... public AA { get; set; } }
然后你可以使用这样的东西:
public IEnumerable GetAll(string id) { var a = _ctx.A.Where(x => x.Id == id).ToList(); _ctx.Base.OfType().Include(e => e.SomeClass).Where(e => eAId == id).Load(); _ctx.Base.OfType().Include(e => e.SomeOtherClass).Where(e => eAId == id).Load(); return a; }
可以使用相同的想法,没有反向导航属性,但使用返回的基本ID作为filter:
public IEnumerable 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().Select(b => b.Id)); db.Base.OfType().Include(e => e.SomeClass) .Where(e => baseIds.Contains(e.Id)).Load(); baseIds = a.SelectMany(e => e.Bases.OfType().Select(b => b.Id)); db.Base.OfType ().Include(e => e.SomeOtherClass) .Where(e => baseIds.Contains(e.Id)).Load(); return a; }
你自己的问题不在Select(y=>y.SomeClass)
,如果你试图从查询中删除它并再次执行你的查询,你会遇到同样的问题。 您不能将inheritance的类型作为子类进行查询,并且您希望entity framework能够处理所有事情。
如果你查看你的数据库,表Base
有一个对A
的引用,它是从A到Base的1-many关系。
您可以通过在类Base
添加导航属性A
来获取A.Id = something
所有Base
实体,并在DbContext中添加DbSet
然后您的查询将如下所示
var details = _ctx.Bases.OfType() .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().Select(m=> new { Id = m.Id, Name = m.Name, SomeClass = m.SomeClass }); }
希望对你有帮助