扩展Expression表达式树,实现EF动态条件查询

在我们写一些管理系统后台的时候,经常会出现带多个查询参数的情况。如果按照一般方法就是if里面嵌套if-else 多层,这样代码看起来很乱。

我们通过扩展表达式树就可以实现这些功能。

//主方法
public static void Main(string[] args)
{
    MyWhere<tb_test> where = new MyWhere<tb_test>();
    //if (xxxx)
    where.And(m => m.id >= 2);
    //if(xxxx)
    where.And(m => m.name.Contains("test"));
    //where.Or(m => m.name.Contains("test"));

    var result = new List<tb_test>();
    using (MysqlTestDB db = new MysqlTestDB())
    {
        result = db.tb_tests.Where(where.GetExpression()).ToList();
    }

    foreach (var item in result)
    {
        Console.WriteLine("id: "+ item.id + ",name: "+item.name);
    }
}
//MyWhere工具类
public class MyWhere<T>
{
    private Expression<Func<T, bool>> _expressions = e => true;

    public void And(Expression<Func<T, bool>> exp)
    {
        _expressions = _expressions.AndAlso(exp, Expression.AndAlso);
    }

    public void Or(Expression<Func<T, bool>> exp)
    {
        _expressions = _expressions.AndAlso(exp, Expression.OrElse);
    }

    public Expression<Func<T, bool>> GetExpression()
    {
        return _expressions;
    }
}
//Expressing扩展类
public static class ExpressionExtensions
{
    public static Expression<Func<T, bool>> And<T>(
        this Expression<Func<T, bool>> first, Expression<Func<T, bool>> secend)
    {
        return first.AndAlso(secend, Expression.AndAlso);
    }

    public static Expression<Func<T, bool>> Or<T>(
        this Expression<Func<T, bool>> first, Expression<Func<T, bool>> secend)
    {
        return first.AndAlso(secend, Expression.OrElse);
    }

    public static Expression<Func<T, bool>> AndAlso<T>(
        this Expression<Func<T, bool>> expr1, Expression<Func<T, bool>> expr2,
        Func<Expression,Expression,BinaryExpression> func)
    {
        var parameter = Expression.Parameter(typeof(T));

        var leftVisitor = new ReplaceExpressionVisitor(expr1.Parameters[0],parameter);
        var left = leftVisitor.Visit(expr1.Body);

        var rightVisitor = new ReplaceExpressionVisitor(expr2.Parameters[0], parameter);
        var right = rightVisitor.Visit(expr2.Body);

        return Expression.Lambda<Func<T, bool>>(func(left, right), parameter);
    }

    private class ReplaceExpressionVisitor : ExpressionVisitor
    {
        private readonly Expression _oldValue;
        private readonly Expression _newValue;

        public ReplaceExpressionVisitor(Expression oldValue, Expression newValue)
        {
            _oldValue = oldValue;
            _newValue = newValue;
        }

        public override Expression Visit(Expression node)
        {
            if (node == _oldValue)
                return _newValue;

            return base.Visit(node);
        }
    }
}

数据库:

 

 结果截图:

1-当 选择 And 包含 "test" 时

 

2-当选择 Or 包含 "test" 时

 

posted @ 2020-11-26 15:35  学无止境-小蜗牛  阅读(899)  评论(0编辑  收藏  举报