[C#]利用 DynamicLinq 完成简单的动态表明式创设查询

作者:编程技术
using Abp.Runtime.Caching;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Linq.Expressions;
using System.Reflection;
using System.Text;

namespace Abp.Linq.Expressions
{
    public class ExpressionBuilder<TEntity, TSearchDto>
    {
        // 其实这里也可以通过传入 params Expression<Func<TRelateEntity, object>>[] selectFields 来构建
        public Expression<Func<TEntity, bool>> Build(string[] excludeFields, TSearchDto dto)
        {
            var parameters = GenerateParametersDictionary(excludeFields, dto);

            StringBuilder sb = new StringBuilder();
            var fieldNames = parameters.Keys.ToList();

            // 动态拼接
            for (int i = 0; i < fieldNames.Count; i  )
            {
                sb.Append(fieldNames[i]).Append($" == @{i}").Append(" && ");
            }

            var lambdaStr = sb.ToString();
            lambdaStr = lambdaStr.Substring(0, lambdaStr.Length - " && ".Length);

            // 构建表达式
            return DynamicExpressionParser.ParseLambda<TEntity, bool>(new ParsingConfig(), false, lambdaStr, parameters.Values.ToArray());
        }

        // 构建参数/值键值对,如果参数值为 NULL 则不进行构建
        private Dictionary<string, object> GenerateParametersDictionary(string[] excludeFields, TSearchDto dto)
        {
            var typeInfo = typeof(TSearchDto);
            var properties = typeInfo.GetProperties();
            var parameters = new Dictionary<string, object>();

            foreach (var property in properties)
            {
                var propertyValue = property.GetValue(dto);

                if (propertyValue == null) continue;
                if (excludeFields == null) continue;
                if (excludeFields.Contains(property.Name)) continue;
                if (parameters.ContainsKey(property.Name)) continue;

                parameters.Add(property.Name, propertyValue);
            }

            return parameters;
        }
    }
}

 1分分快三计划 1    public static IEnumerable<Customers> GetCustomersFunc2(string[] keywords)
 2分分快三计划 2分分快三计划 3    分分快三计划 4{
 3分分快三计划 5        //须要援引System.Linq.Dynamic。Dynamic.cs文件可在LinqSamples中找到
 4分分快三计划 6
 5分分快三计划 7        DataClassesDataContext dc = new DataClassesDataContext();
 6分分快三计划 8        string queryString = "";
 7分分快三计划 9        foreach (string keyword in keywords)
 8分分快三计划 10分分快三计划 11        分分快三计划 12{
 9分分快三计划 13            //原形为(c=>c.CompanyName.Contains(keyword1)) || (c=>c.CompanyName.Contains(keyword2)) || 分分快三计划 14
10分分快三计划 15            queryString  = "CompanyName.Contains(""   keyword   "") or ";
11分分快三计划 16        }
12分分快三计划 17
13分分快三计划 18        //与false举行逻辑或运算,为了幸免queryString中末了的or现身语法错误
14分分快三计划 19        queryString  = "1=0";
15分分快三计划 20        return dc.Customers.Where(queryString);
16分分快三计划 21    }
17分分快三计划 22

多规格之间的OCRUISER查询

纵然不菲场馆下我们都以使用Linq中的where关键字来拼接查询条件,不过有风流罗曼蒂克种须要Linq查询确实满意不断大家,那正是多规格之间是OWrangler的涉嫌。因为只要大家用Linq可能链式方法出来的写出来的SQL语句中的where条件前面将都以and关系,这时候我们必须要用链式方法来进展拆分才行。

分分快三计划 23分分快三计划 24View Code

 1 public List<DutyModel> GetList(DutyModel dutyModel) 
 2 { 
 3     using (UserOrgDemo2Entities Context = new UserOrgDemo2Entities()) 
 4     { 
 5         IQueryable<TB_DUTY> result = Context.TB_DUTY.AsQueryable(); 
 6         System.Linq.Expressions.Expression<Func<TB_DUTY, bool>> expressionDUTY = DynamicLinqExpressions.True<TB_DUTY>(); 
 7 
 8         if (!(dutyModel.RANK_NO == 0)) 
 9             expressionDUTY.Or(duty => duty.RANK_NO == dutyModel.RANK_NO); 
10         if (!string.IsNullOrEmpty(dutyModel.USER_PRIV)) 
11             expressionDUTY.Or(duty => duty.USER_PRIV == dutyModel.USER_PRIV); 
12 
13        return result.Where(expressionDUTY).Select(tb_duty=>new DutyModel(){ USER_PRIV=tb_duty.USER_PRIV}).ToList(); 
14     } 
15 }

那边有个主要正是鬼子(预计是相比厉害的长辈,在这里多谢了!)写的二个*.cs文件,里面是Expression<T>表达式文件的恢宏方法,首要就是用来进行多规格Or、And之间构成查询用的。

怀有说借使多规格构成查询之间是and关系足以平素动用Linq,若是是or或然是or与and一齐,那么能够使用方面这种链式查询艺术。

小结:其实说了那么多指标只有一个,LINQ的分析进程不要独有八个“提供程序翻译成SQL”的历程,而是包涵了八个级次,多个经过的处理,LINQ的写法很三种,原理应该是大半的,只要大家在写LINQ的时候综合考虑那多少个管理进程,应该对我们应对复杂的查询很有利于。

 

作者:王清培

出处:

本文版权归小编和微博共有,款待转载,但未经笔者同意必需保留此段评释,且在文章页面分明地方给出最早的文章连接,不然保留追究法律义务的任务。

纯手工塑造表明式树亦非不可能,只是略微麻烦,而作者辈则足以信任 System.Linq.Dynamic.Core 来方便的完结动态查询语句拼接。

3.披着Linq的假相拼接SQL语句

生机勃勃:LINQ实施表明式

在切磋LINQ的历程中,参照他事他说加以考查了累累技能文章还应该有技能书籍,确实无疑的是Linq to Provider的调用入口都以将拉姆da表明式深入分析成Expression<T>表明式对象,跟Linq to Object区别,Linq to Object是将Lambda直接深入深入分析成泛型Func类型的嘱托,不过大家相当多个人满含自己要好都忽视了二个非常的大的内部原因,正是Provider在其间将对Expression<T>举办实践,并不是大家所精通的那么将表明式Expression<T>对象完全深入解析成等价的SQL,也便是说Expression<T>并不是大家说见到的那么单纯,它兼具双重上下文逻辑在此中。

作者们都以从来动用LINQ作为查询接口,VS在结尾编写翻译的时候肩负对LINQ的语法举行剖析並且翻译成对应的扩张方法调用。大家忽略二个要害的环节,就是VS对LINQ进行分析翻译的时候是会推行LINQ表明式的,这一点特别重要。以前自身直接认为VS只担任将LINQ的表达式翻译成等价的壮大方法调用,后来发现VS为了知足我们在最先不能显著目的条件的动静下进行Where字句的拼凑,允许大家在编写LINQ语句的时候带有逻辑判别表明式在里边,那几个效应对我们实行多规格构成查询时一定低价,无需在开展IF、ELSE的多少个决断,只需求自可是然的在LINQ中的第二个表明式中张开剖断就能够了。追求高贵代码的老同志特别不希望在二个既有LINQ查询又带有链式查询的章程中用三种查询情势,若是LINQ能满意大多数的查询作用那最完备;

为了印证LINQ在编译时会被VS实施,我们用LINQPad工具看一下便知;

LINQ查询表明式:from truck in TB_CX_TRUCKs where 1==1 select truck

LINQ等价的链式方法: TB_CX_TRUCKs.Where (truck => True)

图1:

分分快三计划 25

若无实行按道理是平昔深入分析成Lambda的格式(truck)=>1==1才对,然后让LINQ to Provider提供程序负责管理才对,可能感到未有实质的情致反正是恒等的表明式所以解析成这么。我们在换豆蔻年华种写法看看;

LINQ查询表明式:from truck in TB_CX_TRUCKs where string.IsNullOrEmpty("1111") select truck

LINQ等价的链式方法:TB_CX_TRUCKs.Where (truck => String.IsNullOrEmpty ("1111"))

图2:

分分快三计划 26

经过能够得出八个结论,LINQ语句是会被奉行和剖判的三个动作,在还未进去到提供程序时已经能够见到LINQ是足以顺便一些实行逻辑在里边的,实际不是终极的SQL执行逻辑。

表达式的管理能够分为常量表明式和动态变量表明式,常量表明式在VS编写翻译的时候就足以一直总结表明式是不是是true、false。而动态变量表明式则供给在前期进行表明式剖析的时候总结的,换句话说Linq to Provider中的Provider提供程序是具备高智力商数力的表明式推行器,不止是对表明式等价解析中间还夹杂着对表达式分析的自定义逻辑代码。

打个假诺,大家都有过拼接查询条件的资历,分界面上有N个查询条件字段,须求依据客商是不是填写了哪个字段举行动态的拼接进LINQ语句中去。日常大家都会开展if的论断才行,因为我们都觉着Where后边的基准表明式是一贯被剖析成对应逻辑的SQL语句,所以如若拼接进去的都以被深入深入分析成SQL的Where子句。由于LINQ是无法拆分开来举行组装的,必得二遍写完才具由此编译。所以大家都在运用着询问扩大方法开展数量查询,那样的窘况使大家力不能够支看出LINQ的幽雅,反而一直用不到。

因此阅览LINQPad工具深入剖析的SQL语句,开掘LINQ查询表达式在提供程序内部将被施行、解析多少个经过,跟VS的进度是如出黄金时代辙的,能试行先实行,然后拆解深入分析,深入分析是独当一面在最先实行过后的根底上的。大家依然来看叁个比较轻巧的LINQ深入分析后的SQL和链式方法;

LINQ查询表明式:from truck in TB_CX_TRUCKs where 1==1 ||truck.LICENSE_NUMBER.Length<10 select truck

LINQ等价的链式方法:TB_CX_TRUCKs.Where (truck => (True || (truck.LICENSE_NUMBER.Length < 10)))

图3:

分分快三计划 27

比较链式方法,很刚强VS先对1==1表达式实行了实行并赶回true作为后边全体表明式的后生可畏部分拼接进Where链式方法,所以先实行再剖析七个进度。然后大家对最终的SQL进行深入解析,未有见到别的Where语句,为啥吧?是因为提供程序在里面临表明式实行了实践并解析了大家想要的输出结果,也不清楚这么的成效是否为了满意我们多规格拼接的主题材料。

出于Where方法里面包车型地铁Lambda表明如若被推行的话,那么将不会实行(truck.LICENSE-NUMBE奥迪Q7.Length<10),所以那一点为大家的多规格拼接提供了接口。

大家看一下多规格构成查询示例:

分分快三计划 28

将分界面上的查询实体传入到多少访谈层之后:

分分快三计划 29分分快三计划 30View Code

 1 public List<Truck> GetList(Truck truckModel) 
 2 { 
 3     using (KJtest0817Entities DbContext = new KJtest0817Entities()) 
 4     { 
 5         var resultList = from truck in DbContext.TB_CX_TRUCK 
 6                          where string.IsNullOrEmpty(truckModel.ENGINE_NUMBER) || truck.ENGINE_NUMBER == truckModel.ENGINE_NUMBER 
 7                          where string.IsNullOrEmpty(truckModel.LICENSE_NUMBER) || truck.ENGINE_NUMBER == truckModel.LICENSE_NUMBER 
 8                          select new Truck() 
 9                          { 
10                              BRAND = truck.BRAND 
11                          }; 
12         return resultList.ToList(); 
13     } 
14 }

这么的查询LINQ确实很雅观,比起早先的IFELSE判别也省事超多。

分分快三计划 31分分快三计划 32View Code

1 IQueryable<TB_CX_TRUCK> queryList = DbContext.TB_CX_TRUCK.AsQueryable();//初始化一个IQueryable对象 
2 if (!string.IsNullOrEmpty(truckModel.LICENSE_NUMBER)) 
3        queryList = queryList.Where(truck => truck.LICENSE_NUMBER.Contains(truckModel.LICENSE_NUMBER)); 
4 if (!string.IsNullOrEmpty(truckModel.TRUCK_MODEL_CODE)) 
5        queryList = queryList.Where(truck => truck.TRUCK_MODEL_CODE.Contains(truckModel.TRUCK_MODEL_CODE));

倘诺有那些个查询条件,那么大家将要写过多这么的判断代码,即不方便人民群众也不雅观。

分分快三计划 33

(注:查看大图)

生平接收 LINQ 实香港行政局地简易的规范拼接查询经常都会如此操作:

在拓宽多少查询时,平时遇到需求动态营造查询条件。使用LINQ落成那个供给大概会比原先拼接SQL语句更麻烦一些。本文介绍了3种运营时动态创设查询条件的不二等秘书籍。
本文中的例子最后落到实处的都以同叁个成效,从诺思wind数据库Customers表中检索出CompanyName列带有keywords中大肆元素的项。keywords是个字符串数组,该数董事长度在编写翻译时是不显明的。思路及措施求证写在代码注释中.
1.表达式树

  • 1.LINQ施行表明式

能够看到已经变得老大简练,这里独有看做一得之见,其实还恐怕有越多高端的用法,这里不再赘述。

 1分分快三计划 34    public static IEnumerable<Customers> GetCustomersFunc3(string[] keywords)
 2分分快三计划 35分分快三计划 36    分分快三计划 37{
 3分分快三计划 38        //那几个措施其实是伪Linq,大旨如故在拼接SQL语句,所以就非常的少解释了
 4分分快三计划 39        DataClassesDataContext dc = new DataClassesDataContext();
 5分分快三计划 40        string sqlQuery = "SELECT [CustomerID], [CompanyName], [ContactName], [ContactTitle], [Address], ";
 6分分快三计划 41        sqlQuery  = "[City], [Region], [PostalCode],[Country], [Phone], [Fax] FROM [dbo].[Customers]  WHERE ";
 7分分快三计划 42        foreach (string keyword in keywords)
 8分分快三计划 43分分快三计划 44        分分快三计划 45{
 9分分快三计划 46            sqlQuery  = "([CompanyName] LIKE '%"   keyword   "%' ) OR ";
10分分快三计划 47        }
11分分快三计划 48        sqlQuery  = "(1=0)";
12分分快三计划 49        return dc.ExecuteQuery<Customers>(sqlQuery);
13分分快三计划 50    }
14分分快三计划 51
15分分快三计划 52

阅读目录:

public class SearchInputDto
{
    public string ConditionA { get; set; }
    public int? ConditionB { get; set; }
    public string ConditionC { get; set; }
}

 1分分快三计划 53    public static IEnumerable<Customers> GetCustomersFunc1(string[] keywords)
 2分分快三计划 54分分快三计划 55    分分快三计划 56{
 3分分快三计划 57        DataClassesDataContext dc = new DataClassesDataContext();
 4分分快三计划 58
 5分分快三计划 59        //创建二个静态类型为Customers的参数表明式
 6分分快三计划 60        ParameterExpression c = Expression.Parameter(typeof(Customers), "c");
 7分分快三计划 61
 8分分快三计划 62        //创建二个恒等于false的表明式,用于与下部的发表式取并集
 9分分快三计划 63        Expression condition = Expression.Constant(false);
10分分快三计划 64        foreach (string keyword in keywords)
11分分快三计划 65分分快三计划 66        分分快三计划 67{
12分分快三计划 68            //该表明式用于判别三个Customers类的CompanyName属性的值是不是带有了要害字keyword
13分分快三计划 69            Expression con = Expression.Call(                                   
14分分快三计划 70                Expression.Property(c, typeof(Customers).GetProperty("CompanyName")),
15分分快三计划 71分分快三计划 72                typeof(string).GetMethod("Contains", new Type[] 分分快三计划 73{ typeof(string) }),
16分分快三计划 74                Expression.Constant(keyword));
17分分快三计划 75
18分分快三计划 76            //与前边的condition表明式举办逻辑或运算。
19分分快三计划 77            //假若要寻觅的项供给包蕴keywords中的全数主要字,则可使用Expression.And(con, condition)
20分分快三计划 78            //并且将Expression condition = Expression.Constant(false);
21分分快三计划 79            //改成Expression condition = Expression.Constant(true);
22分分快三计划 80            condition = Expression.Or(con, condition);                         
23分分快三计划 81        }
24分分快三计划 82
25分分快三计划 83        //创制二个以八个Customers类作为参数并回到bool类型的委托
26分分快三计划 84分分快三计划 85        Expression<Func<Customers, bool>> end = Expression.Lambda<Func<Customers, bool>>(condition, new ParameterExpression[] 分分快三计划 86{ c });
27分分快三计划 87
28分分快三计划 88        //使用刚才营造的尺度实行查询
29分分快三计划 89        var result = dc.Customers.Where(end);
30分分快三计划 90        return result;
31分分快三计划 91    }
32分分快三计划 92

到近些日子停止大家对LINQ的执行原理已经很理解了,从它的刚开始阶段构想到它的确为大家所用都有足够的凭证,不过如同难点并从未大家想的那么粗略,难题连连在我们接纳中不仅现身特别是新本领的行使,当然有毛病工夫有开辟进取。

第一去 NuGet 当中找寻 System.Linq.Dynamic.Core 库,安装之后大家来再度编辑此前的查询范例,首先大家来写叁个营造器,用于创设大家的表达式树:

2.使用System.Linq.Dynamic

在看本篇文章此前本身若是您已经怀有自己前面深入分析的一些规律知识,因为那章所要讲的剧情是起家在前头的大器晚成层层知识点之上的,为了确认保证你的读书顺遂提出你先读书小编的LINQ连串小说的前几篇恐怕您曾经具有相比浓郁的LINQ原理知识系统,幸免拖延您的难得时间。

既是是字符串那么就足以凑合,大家来做一下改建。

她的平常化用法如下:

public Task Search(SearchInputDto input)
{
    var queryResult = _db.Where(z=>(input.ConditionA == null || z.Name == input.ConditionA) 
                                && (input.ConditionB == null || z.Number == input.ConditionB)
                                && (input.ConditionC == null || z.Address == input.ConditionC));

    // 执行其他操作...

    return Task.FromResult(0);
}

官方 WIKI 地址:

因为我们前端传入的条件不是一定的,所以有超级大希望会并发局地尺度还未传来的气象,假使是 SQL 的动态拼接 SQL 就能够了,而 Linq 你势必是可望而不可及动态拼接的,唯有谐和营造一个表明式树传入到 IQuerable<T>.Where(Expression<Func<T,bool>> expression) 里面进行询问。

此间有八个规格,是后边一个传入的检索条件,然后大家来编排多少个查询语句:

var query = db.Customers
              .Where("City == @0 and Orders.Count >= @1", "London", 10)
              .OrderBy("CompanyName")
              .Select("new(CompanyName as Name, Phone)");

用法超轻易,用刚刚的代码作为一个事例:

public Task Search(SearchInputDto input)
{
    var builder = new ExpressionBuilder<EntityA,SearchInputDto>();
    var queryResult = _db.Where(builder.Build(null,input));

    // 执行其他操作...

    return Task.FromResult(0);
}

本文由分分快三计划发布,转载请注明来源

关键词: 分分快三计划 C# .NET Framewo LINQ C#、F#