我有一个基于字符串的搜索参数列表:
即 {"部分名称1", "部分名称2", "部分名称3",..., "部分名称(N)"}我永远不会事先知道N的大小。
我想通过迭代此字符串集合来编写 Linq(Linq-to-Entities)"OR"查询,并编写一个等效于以下查询的查询:
var specialFolk = people.Where(p => p.Name.Contains("partialName1") || p.Name.Contains("partialName2") || p.Name.Contains("partialName3") || ... || p.Name.Contains("partialName(N)"));
下面的代码演示了我要执行的操作。 但它不起作用,它只是我想用来以可组合的方式构建 OR 查询的概念的例证
List<string> searchPhrases = searchPhraseGiveToUsFromAbove;
IQueryable<Person> personQuery;
foreach(string searchPhrase in searchPhrases)
{
personQuery = personQuery.Where(p=>p.Name.Contains(searchPhrase))
}
有什么办法可以做到这一点吗?
你应该以相反的方式比较它,就像:
var query = personQuery.Where(p => searchPhrases.Any(r=> p.Name.Contains(r));
感谢@GertArnold我通过他关于谓词生成器的评论找到了自己的方式。
快速介绍"由谓词生成器编写查询的 c# linq"
我找到了一个 LINQKit 的"linq": http://www.albahari.com/nutshell/linqkit.aspx
现在我知道SO不喜欢链接作为答案,但我不确定我是否会抄袭(一些建议会很有用)
谓词生成器非常酷,可以轻松地以编程方式编写查询(复制自 albahari 网站):
IQueryable<Product> SearchProducts (params string[] keywords)
{
var predicate = PredicateBuilder.False<Product>();
foreach (string keyword in keywords)
{
string temp = keyword;
predicate = predicate.Or (p => p.Description.Contains (temp));
}
return dataContext.Products.Where (predicate);
}
然后有一条注释"如果使用实体框架查询,请将最后一行更改为:"
return objectContext.Products.AsExpandable().Where (predicate);
但是,我想将这些谓词链接成更复杂的内容,结果我被一个错误难住了:
参数"f"未绑定在指定的 LINQ 到实体查询表达式中。
这让我想到了皮特·蒙哥马利(Pete Montgomery)的一篇名为《通用谓词生成器》的博客。
事实证明,正如Pete所解释的那样,由于依赖于InvocationExpressions,Albahari版本不能很好地与实体框架配合使用。如果您使用的是 EF,Pete 关于此的博客非常值得一读。
同样,我不想只是复制和粘贴他的解决方案(这是他的,他免费提供),但我将展示我能够构建的查询,最终解决了我的问题:
private IQueryable<Show> BuildQueryForLibrarySearchTerms(IEnumerable<LibraryShowSearchTerm> searchTerms)
{
IQueryable<Show> query = _repository.Get();
IEnumerable<LibraryShowSearchTerm> includeTerms = searchTerms.Where(st=>st.Exclude.Equals(false));
IEnumerable<LibraryShowSearchTerm> excludeTerms = searchTerms.Where(st=>st.Exclude.Equals(true));
var predicate = LinqPredicateBuilder.False<Show>();
var includePredicate = LinqPredicateBuilder.False<Show>();
foreach (LibraryShowSearchTerm searchTerm in includeTerms)
{
string temp = searchTerm.SearchTerm;
includePredicate = includePredicate.Or(show => show.ShowTitle.Contains(temp));
}
var excludePredicate = LinqPredicateBuilder.True<Show>();
foreach (LibraryShowSearchTerm searchTerm in excludeTerms)
{
string temp = searchTerm.SearchTerm;
excludePredicate = excludePredicate.And(show => !show.ShowTitle.Contains(temp));
}
predicate = includePredicate.And(excludePredicate);
return query.Where(predicate);
}
虽然我已经给出了这个作为答案,而且确实如此。我没有这样标记它,因为这不是我要给出的答案,如果皮特或约瑟夫(阿尔巴哈里)遇到这个问题并希望创建一个答案,我会这样标记它。