使用Func<>在LINQ查询中

时间:2014-10-28 20:13:32

标签: c# linq func

我在Func<ProductItemVendor, bool>中存储了CompareProductItemVendorIds。我想在LINQ查询中使用该表达式。

以下是合法的:

var results =
    Repository.Query<ProductItemVendor>().Where(CompareProductItemVendorIds);

但是,以下内容不合法:

var results = from v in Repository.Query<ProductItemVendor>()
              where CompareProductItemVendorIds(v)
              select v;

此代码产生错误:

  

LINQ to Entities中不支持LINQ表达式节点类型“Invoke”。

问题:

  1. 为什么这些陈述如此不同,以至于我的Func<>合法而不是另一个?我以为他们基本上都做了同样的事情。

  2. 我怎样才能做到这一点?我是否必须明确地将Func<>创建为Expression<Func<>>

  3. 请在Using Expression<Func<>> in a LINQ Query查看我的相关问题。

2 个答案:

答案 0 :(得分:11)

Expression<Func<T,bool>>Func<T,bool>之间存在很大差异。第一个是表达式树。您可以将其视为代码描述。 Linq to Entities需要表达式树。因为它需要构建SQL查询。因此需要将代码描述为将相同的操作转换为SQL。

第二个,Func<T,bool>是一个带有指定签名的简单方法。这里没什么特别的。为什么它在这里合法:

Repository.Query<ProductItemVendor>().Where(CompareProductItemVendorIds);

很简单。有两种Where扩展方法。一个前IQueryable<T>,它需要表达式树(将被翻译成SQL查询)。另一个是IEnumerable<T>的扩展,它需要用于内存中集合过滤的常规方法(通常的C#代码)。因此,你没有表达树,选择后者。这里没有生成SQL。这是你的情况。

现在第二个查询:

from v in Repository.Query<ProductItemVendor>()
where CompareProductItemVendorIds(v)
select v

实际上它不是同一个查询。它相当于

Repository.Query<ProductItemVendor>().Where(v => CompareProductItemVendorIds(v));

这里有lambda表达式,可以转换为表达式树。还使用了另一个Where扩展名 - 一个用于IQueryable<T>。因此,Linq to Entities尝试将此表达式树转换为SQL。但它应该转换成什么?是的,调用一些内存中的方法。当然,Linq to Entities没有这样做。

为了使您的查询有效,您应该使用Expression<Func<T,bool>>。您可以手动构建它,也可以使用lambda表达式。

答案 1 :(得分:5)

你的第一个版本的工作原因是Linq过于聪明,因为它有自己的优点。相当于你的第一个版本实际上是

IEnumerable<ProductItemVendor> temp = Repository.Query<ProductItemVendor>().AsEnumerable();
var results = temp.Where(CompareProductItemVendorIds);

因此,当您执行查询时,您将返回数据库中的每一行,然后在本地计算机上的内存中执行Where

要获取要在数据库上执行的Where子句,您必须将CompareProductItemVendorIds的类型更改为Expression<Func<ProductItemVendor, bool>>

没有办法转换&#34;从Func<TIn, TOut>Expression<Func<TIn. Tout>>,您必须将代码重写为最初为表达式,然后您可以通过调用Func<TIn, TOut>

转换为CompareProductItemVendorIds.Compile()
Expression<Func<ProductItemVendor, bool>> CompareProductItemVendorIds = //...
Func<ProductItemVendor, bool> CompareProductItemVendorIdsAsFunc = CompareProductItemVendorIds.Compile();