EF Eager提取派生类 [英] EF Eager fetching derived class

查看:116
本文介绍了EF Eager提取派生类的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用EF6,并尝试渴望获取对象的整个结构。问题是我使用继承。



让我们说我有这个课程。



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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆