是否有必要不在LINQ查询中使用方法?

时间:2010-02-21 11:26:25

标签: linq linq-to-nhibernate

在下面的代码中,当我直接在查询中放入“dl.DamageCount> 5”或将“dl.DamageCount> 5”移动到某个方法或函数,然后从查询中调用它时,有什么不同吗?

似乎当我将其移动到方法中时,查询无法正常工作。实际上,无论条件评估如何,函数/方法似乎总是返回true。我正在使用Linq-to-NHibernate。

 var q = from dl in session.Linq<DamageList>()
            where
            dl.DamageCount > 5

1 个答案:

答案 0 :(得分:4)

您可以做的最好的事情是在Expression<>中捕获谓词。已经将一种方法编译为IL,因此Linq提供程序无法将其拆分。

Expression<Func<DamageList, bool>> predicate = item => item.DamageCount > 5;

然后,您可以将该谓词直接传递给Where

var q = session.Linq<DamageList>().Where(predicate);

如果要动态组合两个这样的表达式,可以将两者的代码写入一个表达式,也可以在单独的表达式中捕获它们。这很复杂,因为你需要每个人都引用传入的item。这实际上是一个不同的问题,已被问到:How do I dynamically create an Expression<Func<MyClass, bool>> predicate?

您可以使用&amp;&amp ;;编写复合谓词。 oerator仍然在表达式中捕获它:

Expression<Func<DamageList, bool>> predicate = 
    dl => dl.DamageCount > 5 && dl.Name.Contains(criteria);

你问在这样的表达式中调用方法 - 好吧,那个例子确实调用了一个方法!

它构建了各种类型的Expression个节点的树。某处包含一个方法调用节点,它表示调用Contains的{​​{1}}方法(假设stringName)。所以这是嵌入在表达式中的方法调用指令的示例。为了使其工作,Linq提供程序必须知道该方法的作用,因此它可以将其转换为等效的SQL(就像典型的ORM系统一样)。

因此,您可以在表达式中嵌入某些标准方法调用 - 它需要Linq提供程序了解它们。 string的方法定义明确,但并非每个提供者都必须能够处理所有这些方法。

Linq提供程序不可能允许您添加自己的扩展来处理额外的方法,但我不知道任何支持(显然如果系统是开源的,您可以添加您的自己的)。

总结一下 - Linq提供程序需要一个表达式节点树,它可以分析它以转换为其他语言(如SQL),以便在另一个上下文(如远程数据库内)中执行。如果编写普通方法,C#编译器会将它们编译为低级可执行IL,而不是表达式节点。所以这就像一个死胡同:没有内置的工具可以将IL转回表达式节点。