使用AsExpandable()时,Linq to Entities的行为有些奇怪。

3
考虑以下Person实体:
public class Person
{
    public int Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

使用以下由PredicateBuilder构建的Expression作为标准:

var byName = PredicateBuilder.True<Person>().And(x => x.FirstName == "Chaim");

当使用以下语法调用时,生成的SQL是正确的(包括WHERE语句):

ctx.Set<Person>().AsExpandable().Where(x => byName.Invoke(x));

然而,当使用这种略微不同的语法调用时,没有 SQL WHERE 参与筛选,筛选是由 Enumerable.Where 来完成:

ctx.Set<Person>().AsExpandable().Where(byName.Invoke);

有什么想法吗?


这非常危险。我调用了 Where(expression.Compile()) 而不是 Where(x => expression.Invoke(x))。后来,在跟踪我们生产数据库时,我发现 select [every column] from Table 没有 where 子句。前者直接来自文档! - dudeNumber4
1个回答

4

方法组不能隐式转换为相应委托类型的Expression。但是可以将方法组隐式转换为匹配签名的委托。因此,只有IEnumerable重载匹配。

当然,并不意味着您需要使用lambda表达式。只需编写:

ctx.Set<Person>().AsExpandable().Where(ByName);

由于你传入的是一个表达式(毕竟,ByName已经是一个Expression<Person,bool>,这正是Queryable.Where<Person>所需要的),因此这将作为查询进行评估,而不是在对象的linq中。


有趣。所以你的意思是 ByName.InvokeFunc<Person, bool>,只匹配 IEnumerable.Where,而 x => ByName.Invoke(x)Expression<Func<Person, bool>>,则匹配 IQueryable.Where - haim770
1
@haim770 x => ByName.Invoke(x)是一个lambda表达式,它可以匹配任何一种。它既可以作为表达式,也可以作为委托。因此,Queryable.WhereEnumerable.Where都是有效的选项,并且它会进入更好的算法。Queryable获胜了。ByName.Invoke只是一个方法组,像任何其他方法组一样,不能转换为Expression,因此Enumerable.Where是唯一可能的有效重载。 - Servy
我明白了。选择“更好的算法”是在运行时执行的?怎么做? - haim770
@haim770 这是在编译时完成的。有关详细信息,请参阅重载解析的规范。 - Servy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接