我写了一个扩展System.Linq
类的方法。我的ContainsAnyWord
方法允许我针对字符串搜索字符串中的所有单词,而不是将一个字符串与另一个字符串进行比较。
这是我写的扩展Linq
public static class LinqExtension
{
public static bool ContainsAnyWord(this string value, string searchFor)
{
if (!string.IsNullOrWhiteSpace(value) && !string.IsNullOrWhiteSpace(searchFor))
{
value = value.ToLower();
IEnumerable<string> tags = StopwordTool.GetPossibleTags(searchFor);
return tags.Contains(value);
}
return false;
}
}
此扩展方法适用于IEnumerable
对象。但是当我想在IQueryable
对象上使用它时,我收到以下错误
LINQ to Entities无法识别方法&#39;布尔值 ContainsAnyWord(System.String,System.String)&#39;方法和这种方法 无法翻译成商店表达。
以下示例效果很好,因为我正在使用列表。
using(var conn = new AppContext())
{
var allUsers = conn.Users.GetAll().ToList();
var foundUsers = allUsers.Where
(
user =>
user.FirstName.ContainsAnyWord("Some Full Name Goes Here")
|| user.LastName.ContainsAnyWord("Some Full Name Goes Here")
).ToList();
}
但以下示例不起作用,因为我正在使用IQueryable
,这会给我上面列出的错误。
using(var conn = new AppContext())
{
var allUsers = conn.Users.Where
(
user =>
user.FirstName.ContainsAnyWord("Some Full Name Goes Here")
|| user.LastName.ContainsAnyWord("Some Full Name Goes Here")
).ToList();
}
如何解决此问题并使此方法可用于IQueryable
对象?
已更新
根据我在下面得到的反馈,我尝试使用IQueryable
来实现这一点
public static IQueryable<T> ContainsAnyWord<T>(this IQueryable<T> query, string searchFor)
{
if (!string.IsNullOrWhiteSpace(searchFor))
{
IEnumerable<string> tags = StopwordTool.GetPossibleTags(searchFor);
return query.Where(item => tags.Contains(item));
}
return query;
}
但这也给了我一个错误
答案 0 :(得分:4)
您必须记住,最后必须将其转换为SQL。
显然ContainsAnyWord无法转换为SQL ...
因此,将您的名字保存在List / Array中并尝试
user => yourlist.Contains( user.FirstName)
EF会将此转换为WHERE ..IN
不需要某种方法,但如果由于某种原因你想要它
internal static class MyClass2
{
public static IQueryable<T> ContainsAnyWord<T>(this IQueryable<T> value, string searchFor) where T: User
{
var names = searchFor.Split(' ').ToList();
return value.Where(u => names.Contains(u.DisplayName));
}
}
您可以像
一样使用它var result=conn.Users.ContainsAnyWord("abc def ght");
答案 1 :(得分:1)
您无法调用查询表达式中的方法,Linq to Entites提供的表达式解析器不知道如何处理。你唯一能做的就是编写一个扩展方法,它接受IQueryable<T>
并在函数内部构建表达式,而不是调用Where(
以下代码完全未经测试,是我想到的。但你需要做这样的事情
public static IQueryable<T> WhereContainsAnyWord<T>(this IQueryable<T> @this, Expression<Func<T, string>> selector, string searchFor)
{
var tags = StopwordTool.GetPossibleTags(searchFor); //You might need a .ToArray() here.
var selectedItems = @this.GroupBy(selector);
var filteredItems = selectedItems.Where(selectedItem => tags.Contains(selectedItem.Key.ToLower()));
var result = filteredItems.SelectMany(x => x);
return result;
}
像
一样使用using(var conn = new AppContext())
{
var allUsers = conn.Users.WhereContainsAnyWord(user => user.FirstName, "Some Full Name Goes Here").ToList();
}
这是一个简单的非通用版本
public static IQueryable<User> WhereContainsAnyWord(this IQueryable<User> @this, string searchFor)
{
var tags = StopwordTool.GetPossibleTags(searchFor); //You might need a .ToArray() here.
return @this.Where(user => tags.Contains(user.DisplayName.ToLower()));
}
像
一样使用using(var conn = new AppContext())
{
var allUsers = conn.Users.WhereContainsAnyWord("Some Full Name Goes Here").ToList();
}
答案 2 :(得分:0)
Linq to Entities将方法转换为数据库表达式。您无法实现System.String的扩展,并期望将其转换为T-SQL表达式,这是内部实体框架所做的。
我的建议是尝试使用预定义的Linq方法。尝试使用Contains方法。