我在找出实现这一目标的最佳方法时遇到了一些麻烦,我将不胜感激。
基本上,我正在设置一个过滤器,允许用户查看与用户名的任意“过滤器”相关联的审核项目的历史记录。
数据源是一个SQL Server数据库,所以我正在使用IQueryable“source”(来自db上下文对象的直接表引用,或者可能是由其他查询产生的IQueryable),应用WHERE过滤器,然后返回结果的IQueryable对象....但我对如何使用这种方法执行OR有点难过。
我已经考虑过表达式的路径,因为我知道如何对它们进行OR,但我还是无法通过“包含”类型评估来弄清楚如何做到这一点,所以我目前正在使用UNION,但我担心这可能会对性能产生负面影响,我想知道如果在arbirary顺序中添加其他过滤器(除了此处显示的用户名过滤),它是否可能无法完全满足我的要求。
以下是我的示例代码:
public override IQueryable<X> ApplyFilter<X>(IQueryable<X> source)
{
// Take allowed values...
List<string> searchStrings = new List<string>();
// <SNIP> (This just populates my list of search strings)
IQueryable<X> oReturn = null;
// Step through each iteration, and perform a 'LIKE %value%' query
string[] searchArray = searchStrings.ToArray();
for (int i = 0; i < searchArray.Length; i++)
{
string value = searchArray[i];
if (i == 0)
// For first step, perform direct WHERE
oReturn = source.Where(x => x.Username.Contains(value));
else
// For additional steps, perform UNION on WHERE
oReturn = oReturn.Union(source.Where(x => x.Username.Contains(value)));
}
return oReturn ?? source;
}
这感觉就像做错事的方式,但它确实有效,所以我的问题首先是,有更好的方法吗?另外,有没有办法用表达式做'包含'或'喜欢'?
(编辑纠正我的代码:为了发布它回滚到工作状态,我显然没有回滚得足够远:))
=============================================
ETA:根据给出的解决方案,这是我的新代码(如果有人对此感兴趣):
public override IQueryable<X> ApplyFilter<X>(IQueryable<X> source)
{
List<string> searchStrings = new List<string>(AllowedValues);
// <SNIP> build collection of search values
string[] searchArray = searchStrings.ToArray();
Expression<Func<X, bool>> expression = PredicateBuilder.False<X>();
for (int i = 0; i < searchArray.Length; i++)
{
string value = searchArray[i];
expression = expression.Or(x => x.Username.Contains(value));
}
return source.Where(expression);
}
(我注意到一个警告:在PredicateBuilder的示例之后,搜索字符串的空集合将返回false(false || value1 || ...),而在我的原始版本中,我假设一个空列表应该只是对于未经过滤的来源。当我想到它时,新版本似乎对我的需求更有意义,所以我采用了它)
=============================================