我从我的数据库中得到拍卖,如下所示:
var auctions = from o in db.auctions select o;
我想将此函数作为 lambda 表达式传递到 .我的 linq 子句过滤我的拍卖结果:
private bool wordsHasProductName(auction a, string[] words)
{
if (!a.product_name.Contains(' ')) // Auction product name is single word - check if
{
if (words.Length > 1) return false; // array is passed, single word is searching
else return a.product_name.Contains(words[0]); // check if product name consists passed string
}
else // Auction product name has more words check if passed string is partially in this product name
{
string[] productName = a.product_name.Split(' ');
var list = new List<string>(words);
foreach (string item in productName)
{
if (list.Contains(item)) list.Remove(item);
}
return list.Count == 0;
}
}
我在我的代码中调用它,在调试时,这一行没有错误,这是我调用的地方.linq 中的 Where() 子句:
string[] words = searchName.Split(' ');
auctions = auctions.Where((a) => wordsHasProductName(a, words));
但是在返回语句结束时,我收到异常错误:
return View(auctions.ToPagedList(pageNumber, pageSize));
错误代码:
类型为"系统.不支持的异常"发生在 EntityFramework.SqlServer.dll但未在用户代码中处理
其他信息:LINQ to 实体无法识别该方法 '布尔词HasProductName(IEP_Projekat.Models.auction, System.String[])' 方法,并且此方法不能转换为 存储表达式。
我怎样才能成功地将完整的布尔函数作为 linq 中的 lambda 表达式发送。哪里()?
正如其他人已经提到的,方法调用不能在 LINQ to Entities 中使用,因为它们不能转换为 SQL。因此,唯一可能的方法是将该方法重写为兼容表达式。另一个问题来了 - 您正在使用string.Split
不支持的方法。
所以你不走运。或者可能不是。这是诀窍。您可以使用以下(IMO 等效)标准,而不是拆分product_name
并检查它是否包含 words
中的每个单词:
words.All(word => (" " + product_name + " ").Contains(" " + word + " "))
用空格将product_name
和word
括起来可以让您在目标字符串的开头、中间或结尾匹配整个单词。它仅使用 EF 支持的构造。
把它们放在一起。该函数将如下所示:
private static Expression<Func<auction, bool>> wordsHasProductName(string[] words)
{
if (words.Length == 1)
{
var word = words[0]; // Avoid ArrayIndex not supported
return a => !a.product_name.Contains(" ") && a.product_name.Contains(word);
}
else
{
return a => words.All(word => (" " + a.product_name + " ").Contains(" " + word + " "));
}
}
和用法:
string[] words = searchName.Split(' ');
auctions = auctions.Where(wordsHasProductName(words));
但是上面的实现并没有产生非常好的SQL查询,特别是对于多个单词。如果通过手动构建谓词表达式来重写它,则会产生更好的 SQL:
private static Expression<Func<auction, bool>> wordsHasProductName(string[] words)
{
Expression<Func<auction, string>> product_name;
Expression condition;
var containsMethod = typeof(string).GetMethod("Contains", new[] { typeof(string) });
if (words.Length == 1)
{
// a => !a.product_name.Contains(" ") && a.product_name.Contains(words[0])
product_name = a => a.product_name;
condition = Expression.AndAlso(
Expression.Not(Expression.Call(product_name.Body, containsMethod, Expression.Constant(" "))),
Expression.Call(product_name.Body, containsMethod, Expression.Constant(words[0])));
}
else
{
// a => (" " + a.product_name + " ").Contains(" " + words[0] + " ")
// && (" " + a.product_name + " ").Contains(" " + words[1] + " ")
// ...
// && (" " + a.product_name + " ").Contains(" " + words[N-1] + " ")
product_name = a => " " + a.product_name + " ";
condition = words
.Select(word => Expression.Call(product_name.Body, containsMethod, Expression.Constant(" " + word + " ")))
.Aggregate<Expression>(Expression.AndAlso);
}
return Expression.Lambda<Func<auction, bool>>(condition, product_name.Parameters);
}
欢迎来到 EF 和表达式的世界:)
不能将此复杂的 C# 逻辑作为可由 EF 提供程序解释的表达式树传递,提供程序最困难的部分是将其转换为 SQL 语句。
因此,您的选择是创建一个存储过程,在其中传入所需的参数,然后使用纯 SQL 编写逻辑。然后,将 SP 映射到 EF 并调用它以返回所需的对象列表。