EF Eager提取派生类 [英] EF Eager fetching derived class
问题描述
让我们说我有这个课程。
DbContext
DbSet< A> A {get;组;
示例课程
public class A
{
public string Id {get;组; }
public IList< Base>基地{get;组;
}
public abstract class Base
{
public int Id {get;组; }
public string Name {get;组;
}
public abstract class Base1:Base
{
public SomeClass SomeClass {get;组; }
}
public class Base2:Base1
{
}
public class Base3:Base1
{
public SomeOtherClass SomeOtherClass {get;组;
}
我得到的错误是:
包含路径表达式必须引用在类型上定义的导航属性。
使用虚线路径作为参考导航属性,选择运算符用于集合导航属性。
为什么它不符合以下条件?
public IEnumerable< A> GetAll(string id)
{
return _ctx.A
.Include(x => x.Bases.OfType< Base1&())(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();
返回列表;
}
编辑:添加了一个似乎有效的新例子。
很快,这是不可能开箱即用的。
建议实现主查询结果,然后执行几个 OfType
查询,必要的 Includes
使用与主要查询,并依靠EF导航属性修复。
它需要 Base
类中的反向导航属性:
public abstract class Base
{
// ...
public AA {get ;组; }
}
然后你可以使用这样的东西:
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; e.SomeOtherClass).Where(e => e.A.Id == id).Load();
return a;
}
同样的想法可以使用w / o反向导航属性,但使用返回基本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))。
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))。
return a;
}
I´m using EF6 and trying to eager fetch the whole structure of an object. The problem is that i´m using inheritance.
Let´s say that i have this classes.
DbContext
DbSet<A> A { get; set; }
Example classes
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 error i get is:
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.
Why doesn´t it work with the following ?
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();
}
New example
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;
}
EDIT: Added a new example that seems to work.
Shortly, it's not possible out of the box.
The only workaround I can suggest is to materialize the master query result, then execute several OfType
queries with the necessary Includes
using the same filter as the master query, and rely on EF navigation property fixup.
It requires an inverse navigation property in the Base
class:
public abstract class Base
{
// ...
public A A { get; set; }
}
Then you can use something like this:
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;
}
The same idea can be used w/o inverse navigation property but with using the returned base Ids as filter:
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;
}
这篇关于EF Eager提取派生类的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!