用PredicateBuilder实现Linq动态拼接查询

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了用PredicateBuilder实现Linq动态拼接查询相关的知识,希望对你有一定的参考价值。

在使用Linq查询的时候,特别是如果你在使用Entiry Framwork,有时会遇到动态查询的情况(客户的查询条件是不固定的拼接查询)。
我们能想到的第一方案应该是拼接SQL,的确这样是可以达到我们的目的的。但这样又会破坏程序的一至性,本来使用Entiry Framwork的目标就是用面向对象的方式操纵数据库,这样我们又要开始写SQL语句了。

其实我一开始也是这样做的直到有一天我们部门的美女程序员给我介绍LinqKit,我才开始用PredicateBuilder来拼接Predicate委托。

PredicateBuilder是LinqKit库的一部分,下面是PredicateBuilder源代码:

using System;
using System.Linq;
using System.Linq.Expressions;

namespace LinqUtil
{
    public static class PredicateBuilder
    {
        public static Expression<Func<T, bool>> True<T>()
        {
            return f => true;
        }

        public static Expression<Func<T, bool>> False<T>()
        {
            return f => false;
        }

        public static Expression<Func<T, bool>> Or<T>(this Expression<Func<T, bool>> expr1,
                                                            Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.OrElse(expr1.Body, invokedExpr), expr1.Parameters);
        }

        public static Expression<Func<T, bool>> And<T>(this Expression<Func<T, bool>> expr1,
                                                             Expression<Func<T, bool>> expr2)
        {
            var invokedExpr = Expression.Invoke(expr2, expr1.Parameters.Cast<Expression>());
            return Expression.Lambda<Func<T, bool>>
                  (Expression.AndAlso(expr1.Body, invokedExpr), expr1.Parameters);
        }
    }
}

这里主要是介绍PredicateBuilder的使用,如想了解PredicateBuilder具体是怎么实现的可以看看这篇文章:传送门

引入PredicateBuilder依赖

  • 用VS的NuGet安装LinqKit
  • 直接引用上面的源码

创建PredicateBuilder对象

var where = PredicateBuilder.True<TrendStatics>();

可以理解为创建一个初始化为True的Predicate。

注意:如果你是要创建一个OR组成的Predicate就不能把它初始化为True因为这样这个表达试永远为True了。

var where = PredicateBuilder.False<TrendStatics>();

可以理解为创建一个初始化为False的Predicate。

注意:如果你是要创建一个AND组成的Predicate就不能把它初始化为False因为这样这个表达试永远为False了。

PredicateBuilder对象拼接

现在你可以对Predicate进行各种拼接了

  • 全And:
  • var where = PredicateBuilder.True<int>();
    where = where.And(x => x >= 50);
    where = where.And(x => x <= 70);
    var res = list.Where(where.Compile());
  • 全Or:
  • var list  = Enumerable.Range(1, 100);
    var where = PredicateBuilder.False<int>();
    where = where.Or(x => x == 50);
    where = where.Or(x => x == 70);
    var res = list.Where(where.Compile());
  • 各种组合:
  • var list  = Enumerable.Range(1, 100);
    var where = PredicateBuilder.True<int>();
    where = where.And(x => x >= 50);
    where = where.And(x => x <= 70);
    var subwhere = PredicateBuilder.False<int>();
    subwhere = subwhere.Or(x => x == 60);
    subwhere = subwhere.Or(x => x == 61);
    where = where.And(subwhere);
    var res = list.Where(where.Compile());

PredicateBuilder对象使用

  • 针对集合Linq查询

你可以这样用:

var res = list.Where(where.Compile());

你还可以这样用:

var res = list.AsQueryable().Where(where);
  • 针对Entity Framework:
var res = table.Where(where.Expand());

转载请注明出处:http://www.cnblogs.com/keitsi/p/5621136.html

以上是关于用PredicateBuilder实现Linq动态拼接查询的主要内容,如果未能解决你的问题,请参考以下文章

linq 多条件查询

Linq To Sql进阶系列用object的动态查询与保存log篇

如何以编程方式将 LINQ 查询转换为正确描述 linq 表达式的可读英文文本?

将 LinqKit PredicateBuilder 用于相关模型(EF Core)

有没有办法将 PredicateBuilder 与 Azure 表存储一起使用?

linq 实现动态 orderby