我最近注意到一些奇怪的东西,Entitiy上的导航属性没有实现IQueryable, 虽然据我所知,检索单个实体然后在导航属性上链接运算符可能会导致许多(每个项目1个)调用数据库,从生成的代码我看到有一个带有子查询结果的大查询(如果可能)在一个大型查询中。
但是我想知道它是如何工作的,因为子查询中的可用重载与在子查询外部的导航属性上调用的重载相同。 问题1:我的猜测是,即使它在IEnuerable上,而any调用本身也是传递到where的表达式的一部分,它然后构建到在哪里生成的单个表达式树并在那里解析而不是作为单独的表达式(因为它本身不是表达式),这是正确的吗?
问题2:如果#1是正确的,如果你在表达式之外创建代码,如果只能在运行时在委托中创建代码,那么它是如何工作的(例如,如果我通过PredicateExprEntityTwo.Compile(),那将如何工作?在q5中,是否会在运行时编译失败,因为编译器在编译时不知道表达式中func的用法?
问题3:假设我有#1和#2正确,这个设计的优点是什么?我遇到的缺点是,对于业务验证,我考虑使用一组带有业务逻辑的谓词来过滤程序中许多地方的相同类型的实体,但是我可能想在子查询中使用它们并且假设#2是正确的,重复使用同一个可能是不可行的吗?
我很抱歉,如果问题听起来有点令人困惑,但我上周才注意到我在子查询中调用了IEnumerables重载,但仍然只有一个EF查询作为输出,我很好奇它是如何工作的
public class Class1
{
void Test()
{
Func<Entity1, bool> PredicateFuncEntityOne = i => i.Id == 2;
Expression<Func<Entity1, bool>> PredicateExprEntityOne = i => i.Id == 2;
Func<Entity2, bool> PredicateFuncEntityTwo = i => i.Id == 2;
Expression<Func<Entity2, bool>> PredicateExprEntityTwo = i => i.Id == 2;
using (var Context = new TestModelContainer())
{
// Works as this expects an expression
var q1 = Context.Entity1Set.Where(PredicateExprEntityOne);
// Works but would call the IEnumerable version
var q2 = Context.Entity1Set.Where(PredicateFuncEntityOne);
// This compiles, any on item.Entity2 expects a func on IEnumerable, not IQueryable overload
var q3 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateFuncEntityTwo));
// This fails for the reason mentioned above
var q4 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateExprEntityTwo));
// Does this work and if so how is it possible?
var q5 = Context.Entity1Set.Where(item => item.Entity2.Any(PredicateExprEntityTwo.Compile()));
}
}
}
答案 0 :(得分:0)
Q1:我也认为这是对的。
Q2:是的,如果您将Func或任何委托传递给表达式,那么编译查询将失败。
我不确定Q3。
但是回过头来,我在EF玩游戏时遇到了类似的问题。我发现将这些关系属性转换为IQueryable并调用方法表达式非常有用。但这可能是一个侥幸。