在LINQ查询中使用Func

我有一个Func存储在CompareProductItemVendorIds 。 我想在LINQ查询中使用该表达式。

看来以下是合法的:

 var results = Repository.Query().Where(CompareProductItemVendorIds); 

但是,以下内容不合法:

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

此代码产生错误:

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

问题:

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

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

请在LINQ查询中的Using Expression <Func >中查看我的相关问题。

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

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

 Repository.Query().Where(CompareProductItemVendorIds); 

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

现在第二个查询:

 from v in Repository.Query() where CompareProductItemVendorIds(v) select v 

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

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

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

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

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

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

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

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

无法从Func “转换”为Expression> Expression> ,你必须重写你的代码最初是一个表达式,然后你可以通过调用CompareProductItemVendorIds.Compile()转换为Func

 Expression> CompareProductItemVendorIds = //... Func CompareProductItemVendorIdsAsFunc = CompareProductItemVendorIds.Compile();