我从我的数据库获得拍卖:
var auctions = from o in db.auctions select o;
我想将此函数作为我的linq的.Where子句中的lambda表达式传递来过滤我的拍卖结果:
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语句的最后我得到了异常错误:
return View(auctions.ToPagedList(pageNumber, pageSize));
错误代码:
发生了'System.NotSupportedException'类型的异常 EntityFramework.SqlServer.dll但未在用户代码中处理
其他信息:LINQ to Entities无法识别该方法 'Boolean wordsHasProductName(IEP_Projekat.Models.auction, System.String [])'方法,这个方法无法翻译成一个 商店表达。
我怎样才能成功在我的linq .Where()中将完整的bool函数作为lambda表达式发送?
答案 0 :(得分:1)
正如其他人已经提到的,方法调用不能在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和表达世界:)
答案 1 :(得分:0)
您不能将这个复杂的C#逻辑作为Expression Tree传递给EF提供程序解释,而提供程序最难的部分就是将其转换为SQL语句。
因此,您可以选择创建一个传入所需参数的存储过程,然后使用纯SQL编写逻辑。然后,将SP映射到EF并调用它以返回所需的对象列表。