5

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

我虽然关于使用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. 客户现在坚持能够执行“而不是”/“或不是”搜索。

为了解决第 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 的强类型。

4

1 回答 1

9

如果您正在寻找更少的行,您可以将 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部分是否正确设置了谓词?据我所知,您正在构建将在稍后执行的表达式,因此您可能只对 final 中的最后一个集合谓词有字面引用迭代,这就是为什么您必须使用临时变量来保存每次迭代的值。

编辑: 如果您想以编程方式否定表达式,这是一个棘手的问题,您可以尝试以下操作:

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;
        }

您可以查看这个问题以获取更多示例。有没有办法否定谓词?

于 2010-06-16T17:31:19.677 回答