Linq PredicateBuilder具有条件AND,OR和NOT过滤器

时间:2010-06-15 09:33:07

标签: c# linq linq-to-sql predicatebuilder

我们有一个使用LINQ to SQL的项目,为此我需要重写几个搜索页面以允许客户端选择是否要执行或< / em>搜索。

我虽然使用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;
}

虽然我对此感到满意,但我有两个问题:

  1. 评估SearchType属性的if / else块感觉它们可能是潜在的代码味道。
  2. 客户现在坚持能够执行'而不是'/'或'搜索。
  3. 为了解决第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);
        }
    }
    

    然而,这感觉有点像kludge,这通常意味着那里有更好的解决方案。任何人都可以推荐如何改善这一点?我知道动态LINQ,但我真的不想失去LINQ的强类型。

1 个答案:

答案 0 :(得分:8)

如果您要寻找更少的线路,可以用三元运算符替换if / else:

query = SearchType == SearchType.And ? PredicateBuilder.True<Job>() : PredicateBuilder.False<Job>();

   foreach (var predicate in predicates)
   {
        query = SearchType == SearchType.And ? query.And(predicate) : query.Or(predicate);
   }

对于'and not' / 'or not'部分,!运算符应该执行此操作。

PD:你测试foreach部分是否正确设置了谓词?,据我所知,你正在构建将在以后执行的表达式,所以你可能只有最后一次迭代中最后一个set谓词的文字引用,这就是为什么你必须使用temp变量来保存每次迭代的值。

修改 如果你想否定一个程序化的表达式,这是一个棘手的,你可以尝试类似的东西:

internal static Expression<Func<Job, bool>> Description(string term, bool invert)
        {
           return NegateExp<Func<Job, bool>>(p => p.Description.Contains(term), invert);
        }

NegateExp方法将类似于:

public static Expression<TDelegate> NegateExp<TDelegate>(Expression<TDelegate> expression, bool inverse)
        {
            if (inverse)
            {
                return Expression.Lambda<TDelegate>(Expression.Not(expression.Body), expression.Parameters);
            }
            return expression;
        }

您可以查看此问题以获取更多示例Is there any way to negate a Predicate?