EF渴望获取派生类
本文关键字:派生 获取 渴望 EF | 更新日期: 2023-09-27 18:07:53
我正在使用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
来获取A.Id = something
所在的所有Base
实体,然后在DbContext中添加DbSet<Base> Bases{get;set;}
,则您的查询将类似于以下
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
});
}
希望这将帮助您