假设我有以下实体
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();
返回所有子实体的列表而没有问题。)
答案 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扩展方法?
使用OfType
,Include
等撰写查询时,您正在使用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>