具有条件 AND、OR 和 NOT 过滤器的 Linq PredicateBuilder
我们有一个使用 LINQ to SQL 的项目,我需要重写几个搜索页面,以允许客户端选择是否要执行和或或搜索。
我想使用 PredicateBuilder 重做 LINQ 查询,并且我认为它工作得很好。我实际上有一个包含我的谓词的类,例如:
internal static Expression<Func<Job, bool>> Description(string term)
{
return p => p.Description.Contains(term);
}
为了执行我正在执行的搜索(为简洁起见,省略了一些代码):
public Expression<Func<Job, bool>> ToLinqExpression()
{
var predicates = new List<Expression<Func<Job, bool>>>();
// build up predicates here
if (SearchType == SearchType.And)
{
query = PredicateBuilder.True<Job>();
}
else
{
query = PredicateBuilder.False<Job>();
}
foreach (var predicate in predicates)
{
if (SearchType == SearchType.And)
{
query = query.And(predicate);
}
else
{
query = query.Or(predicate);
}
}
return query;
}
虽然我对此相当满意,但我有两个问题:
- 评估 a 的 if/else 块SearchType 属性感觉它们可能是潜在的代码味道。
- 客户现在坚持能够执行“与不”/“或不”搜索。
为了解决第 2 点,我认为我可以通过简单地重写我的表达式来做到这一点,例如:
internal static Expression<Func<Job, bool>> Description(string term, bool invert)
{
if (invert)
{
return p => !p.Description.Contains(term);
}
else
{
return p => p.Description.Contains(term);
}
}
然而,这感觉有点像拼凑,这通常意味着有更好的解决方案。谁能建议如何改进这一点?我知道动态 LINQ,但我真的不想失去 LINQ 的强类型。
We have a project using LINQ to SQL, for which I need to rewrite a couple of search pages to allow the client to select whether they wish to perform an and or an or search.
I though about redoing the LINQ queries using PredicateBuilder and have got this working pretty well I think. I effectively have a class containing my predicates, e.g.:
internal static Expression<Func<Job, bool>> Description(string term)
{
return p => p.Description.Contains(term);
}
To perform the search i'm doing this (some code omitted for brevity):
public Expression<Func<Job, bool>> ToLinqExpression()
{
var predicates = new List<Expression<Func<Job, bool>>>();
// build up predicates here
if (SearchType == SearchType.And)
{
query = PredicateBuilder.True<Job>();
}
else
{
query = PredicateBuilder.False<Job>();
}
foreach (var predicate in predicates)
{
if (SearchType == SearchType.And)
{
query = query.And(predicate);
}
else
{
query = query.Or(predicate);
}
}
return query;
}
While i'm reasonably happy with this, I have two concerns:
- The if/else blocks that evaluate a SearchType property feel like they could be a potential code smell.
- The client is now insisting on being able to perform 'and not' / 'or not' searches.
To address point 2, I think I could do this by simply rewriting my expressions, e.g.:
internal static Expression<Func<Job, bool>> Description(string term, bool invert)
{
if (invert)
{
return p => !p.Description.Contains(term);
}
else
{
return p => p.Description.Contains(term);
}
}
However this feels like a bit of a kludge, which usually means there's a better solution out there. Can anyone recommend how this could be improved? I'm aware of dynamic LINQ, but I don't really want to lose LINQ's strong typing.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您正在寻找更少的行,您可以用三元运算符替换 if/else:
对于
'and not' / 'or not'
部分,!
运算符应该执行以下操作诡计。PD:您是否测试了
foreach
部分是否正确设置了谓词?据我记得您正在构建将在稍后时间点执行的表达式,所以您可能仅对最终迭代中的最后一个集合谓词进行文字引用,这就是为什么您必须使用临时变量来保存每次迭代的值。编辑:
如果您想以编程方式否定表达式,这是一个棘手的问题,您可以尝试类似的方法:
并且 NegateExp 方法将类似于:
您可以查看此问题以获取更多示例 有什么方法可以否定谓词吗?
If you are looking for less lines you can replace the if/else with ternary operator:
for the
'and not' / 'or not'
part the!
operator should do the trick.PD: Did you test the
foreach
part is correctly setting the predicates?, as far as i remember you are building the expression that will be executed at later point in time, so you may have a literal reference just to the last set predicate in the final iteration, and that's why you must use a temp variable to save the value of each iteration.EDIT:
If you want to negate a expression programmatic, that's a tricky one, you can try something like:
And the NegateExp method will be something like:
You can take a look at this question for more examples Is there any way to negate a Predicate?