使用Func<>;在LINQ查询中

本文关键字:LINQ 查询 gt Func lt 使用 | 更新日期: 2023-09-27 18:28:06

我在CompareProductItemVendorIds中存储了一个Func<ProductItemVendor, bool>。我想在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<>>

请参阅我在使用表达式<Func<gt>在LINQ查询中。

使用Func<>;在LINQ查询中

Expression<Func<T,bool>>Func<T,bool>之间有很大的差异。第一个是表达式树。你可以把它看作是对代码的描述。实体的Linq需要表达式树。因为它需要构建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表达式。

您的第一个版本之所以有效,是因为Linq过于聪明,不利于自身利益。你的第一个版本实际上是

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

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

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

没有办法将Func<TIn, TOut>"转换"为Expression<Func<TIn. Tout>>,您必须将代码重写为最初的表达式,然后可以通过调用CompareProductItemVendorIds.Compile() 转换为Func<TIn, TOut>

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