如何使用多个条件where子句创建Linq查询

时间:2019-07-20 01:14:23

标签: linq

我有一个带有多个条件where子句的linq查询。当where子句中没有过滤器时,查询将返回表中的所有数据。当where子句中没有过滤器时,如何使linq查询第一次返回0条记录?请参阅下面的代码:

using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Web.Http;
using API.Models;
using System.Linq.Expressions;
namespace API.Controllers
{

// api代码从这里开始

public class MYTABLEController : ApiController
{
    private DataModel db = new DataModel();



    //GET /MYTABLE
    public List<MYTABLE> Get(string filter1 = null,string filter2=null)
    {

        IQueryable<MYTABLE> qry = db.MYTABLE.AsQueryable();
        var searchPredicate = PredicateBuilder.False<MYTABLE>();

        if (!string.IsNullOrWhiteSpace(filter1))
        {

            searchPredicate = searchPredicate.And(a => a.COLUMN1==(filter1);

        }
        if (!string.IsNullOrWhiteSpace(filter2))
        {

            searchPredicate = searchPredicate.And(a => a.COLUMN2==(filter2);

        }

        return qry.Where(searchPredicate).ToList();

    }

// PredicateBuilder https://petemontgomery.wordpress.com/2011/02/10/a-universal-predicatebuilder/

      public static class PredicateBuilder
{
    /// <summary>
    /// Creates a predicate that evaluates to true.
    /// </summary>
    public static Expression<Func<T, bool>> True<T>() { return param => true; }

    /// <summary>
    /// Creates a predicate that evaluates to false.
    /// </summary>
    public static Expression<Func<T, bool>> False<T>() { return param => false; }

    /// <summary>
    /// Creates a predicate expression from the specified lambda expression.
    /// </summary>
    public static Expression<Func<T, bool>> Create<T>(Expression<Func<T, bool>> predicate) { return predicate; }

    /// <summary>
    /// Combines the first predicate with the second using the logical "and".
    /// </summary>
    public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
    {
        return first.Compose(second, Expression.AndAlso);
    }

    /// <summary>
    /// Combines the first predicate with the second using the logical "or".
    /// </summary>
    public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> first, Expression<Func<T, bool>> second)
    {
        return first.Compose(second, Expression.OrElse);
    }

    /// <summary>
    /// Negates the predicate.
    /// </summary>
    public static Expression<Func<T, bool>> Not<T>(this Expression<Func<T, bool>> expression)
    {
        var negated = Expression.Not(expression.Body);
        return Expression.Lambda<Func<T, bool>>(negated, expression.Parameters);
    }

    /// <summary>
    /// Combines the first expression with the second using the specified merge function.
    /// </summary>
    static Expression<T> Compose<T>(this Expression<T> first, Expression<T> second, Func<Expression, Expression, Expression> merge)
    {
        // zip parameters (map from parameters of second to parameters of first)
        var map = first.Parameters
            .Select((f, i) => new { f, s = second.Parameters[i] })
            .ToDictionary(p => p.s, p => p.f);

        // replace parameters in the second lambda expression with the parameters in the first
        var secondBody = ParameterRebinder.ReplaceParameters(map, second.Body);

        // create a merged lambda expression with parameters from the first expression
        return Expression.Lambda<T>(merge(first.Body, secondBody), first.Parameters);
    }

    class ParameterRebinder : ExpressionVisitor
    {
        readonly Dictionary<ParameterExpression, ParameterExpression> map;

        ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map)
        {
            this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>();
        }

        public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp)
        {
            return new ParameterRebinder(map).Visit(exp);
        }

        protected override Expression VisitParameter(ParameterExpression p)
        {
            ParameterExpression replacement;

            if (map.TryGetValue(p, out replacement))
            {
                p = replacement;
            }

            return base.VisitParameter(p);
        }
    }
}

3 个答案:

答案 0 :(得分:0)

首先,我将为此使用谓词构建器。例如this one

这会将您的代码转换为:

IQyeryable<MyTable> qry = db.myTable;
var predicate = PredicateBuilder.True<MyTable>();

if (!string.IsNullOrWhiteSpace(filter1))
{
    predicate = predicate.And(a => a.column1.Contains(filter1));
}
if (!string.IsNullOrWhiteSpace(filter2))
{
    predicate = predicate.And(a => a.column2.Contains(filter2));
}
...

qry = qry.Where(predicate);

现在很容易检查是否添加了任何谓词。如果不是,则predicate只是a => true,这意味着它的主体只是一个ConstantExpression(值:true)。您可以在最后一行的上方添加此检查:

if (predicate.Body is ConstantExpression)
{
    predicate = PredicateBuilder.False<MyTable>();
}

(当然,前提是您不要用另一个谓词,另一个常量表达式替换 predicate,但是我想那没有多大意义)。

答案 1 :(得分:0)

像这样更新此方法:

public List<MYTABLE> Get(string filter1 = null,string filter2=null)
{
    if(string.IsNullOrWhiteSpace(filter1) && string.IsNullOrWhiteSpace(filter2))
        return new List<MYTABLE>();

    IQueryable<MYTABLE> qry = db.MYTABLE.AsQueryable();
    var searchPredicate = PredicateBuilder.False<MYTABLE>();

    if (!string.IsNullOrWhiteSpace(filter1))
    {
        searchPredicate = searchPredicate.And(a => a.COLUMN1==(filter1);
    }
    if (!string.IsNullOrWhiteSpace(filter2))
    {
        searchPredicate = searchPredicate.And(a => a.COLUMN2==(filter2);
    }
    return qry.Where(searchPredicate).ToList();
}

答案 2 :(得分:0)

您可以创建扩展方法:

public static IQueryable<T> WhereIf<T>(
   this IQueryable<T> source, bool condition, 
   Expression<Func<T, bool>> predicate)
{
    return condition ? source.Where(predicate) : source;
}

并以以下方式使用它:

using static System.String;

...

public List<MYTABLE> Get(string filter1 = null,string filter2=null)
{
    return db.MYTABLE
       .WhereIf(!IsNullOrEmpty(filter1), y => y.COLUMN1 == filter1)
       .WhereIf(!IsNullOrEmpty(filter2), y => y.COLUMN2 == filter2)
       .ToList();
}