实体框架 - 渴望加载和继承

时间:2016-04-01 19:39:40

标签: c# entity-framework

假设我有以下实体

class EntityBase
{
    public virtual NavPropType NavPropBase {get; set;}
}

class ChildEntityA:EntityBase
{
    public virtual ChildNavPropTypeA NavPropA {get; set;}
}

class ChildEntityB : EntityBase
{
    public virtual ChildNavPropTypeB NavPropB {get; set;}
}

我希望利用预先加载的导航属性在一个查询中加载所有这些内容。

context.EntitiesBase.Include(e => e.NavPropBase).ToList();

这将加载所有。但是,只会预加载NavPropBase

我尝试连接,但它不起作用。

var r1 = context.EntitiesBase.OfType<ChildEntityA>
    .Include(e => e.NavPropBase)
    .Include(e => e.NavPropA);

var r2 = context.EntitiesBase.OfType<ChildEntityB>
   .Include(e => e.NavPropBase)
   .Include(e => e.NavPropB);

var r = r1.Concat(r2).ToList();

几年前我发现了类似的问题。而且似乎当时不可能。从那以后有什么变化吗?我想知道为什么没有实现这样的功能(任何技术问题?)。我也不确定为什么连接不起作用(同时context.EntitiesBase.ToList();返回所有子实体的列表而没有问题。)

1 个答案:

答案 0 :(得分:0)

您不能连接两个不同类型的列表,虽然它们共享相同的基类型,但泛型类型不同。

要连接两个结果,请尝试使用Cast扩展方法:

var r1 = context.EntitiesBase.OfType<ChildEntityA>()
    .Include(e => e.NavPropBase)
    .Include(e => e.NavPropA).AsEnumerable().Cast<EntityBase>();

var r2 = context.EntitiesBase.OfType<ChildEntityB>()
   .Include(e => e.NavPropBase)
   .Include(e => e.NavPropB).AsEnumerable().Cast<EntityBase>();

var r = r1.Concat(r2).ToList();

foreach(var e in r)
{
   if(e is ChildEntityA)
   {
     var a=(ChildEntityA)e;
     var navProp=a.NavPropA;
   }
   else if( e is ChildEntityB)
   {
     //the same
   }
}

更新

为什么需要调用AsEnumerable扩展方法?

使用OfTypeInclude等撰写查询时,您正在使用IQueryable<T>扩展方法,这些方法用于Linq to Entities提供程序转换您的linq查询到SQL。如果您没有调用AsEnumerable扩展方法,那么您将调用IQueryable<T>.Cast扩展方法,以便在创建SQL查询时也包含方法调用,这就是您收到的原因一个例外,EntityBase没有声明名为NavPropA的导航属性。调用AsEnumerable你告诉你要切换到Linq到Objects,所以你从那个点调用的方法将来自IEnumerable<T>,所以,它们在创建时不会被考虑您的SQL查询,只有您在调用AsEnumerable之前调用的方法。关于在调用ToList扩展方法之前是否仍然延迟的问题,是的,IEnumerable<T>.Cast是通过使用延迟执行实现的,因此,在您调用ToList之前,两个查询都不会执行。< / p>

相关问题