怎么利用表明式树生成动态查询,关于Expression表明式树的拼凑

[翻译]怎么着使用表明式树生成动态查询

在LINQ,表达式树常用于结构化查询,目的财富数量达成了
IQueryable.
比方,LINQ为关系型数据存款和储蓄查询提供了
IQueryable
接口。C#编写翻译器将这一个数据源的查询编写翻译成运营时的表明式树代码。然后查询提供程序能够遍历表达式树数据结构,并转载为适当于数据源的查询语言。

在LINQ中采取表达式树来代表分配给
Expression
类型的拉姆da表达式变量。

那节重要描述了怎么样利用表达式树营造贰个动态LINQ查询。在编写翻译期,动态查询在特殊未知的询问的场合下是十二分实用的。具体育赛事例,贰个应用程序提供了叁个用户接口,最终来允许用户钦点二个或多个谓词来过滤数据。为了利用LINQ查询,这种情况应用程序在运维时务必采纳表明式树来构建多个LINQ查询。

关于Expression表明式树的拼凑

 

多年来在做项目中遇见贰个难题,须要是那样的:

自己要对已经存在的用户进行搜索,能够依附用户的id
或许用户名在那之中的一部分字符来寻觅出来,那样就涌出了两种情形独有id,只有用户名中一部字符,大概全体都有.

咱俩用的MVC+EF5.0的框架,在BLL层举行查询的
时候须求营造lambda表明式来作为查询条件,可是,大家怎么来构建lambda来规定询问的原则吧?大家知道Express<Func<T,bool>>这样的二个参数可以是lambda表明式,可是这里的按法规拼接式无法选拔委托链的样式的.当然还会有一种化解办法,笔者把具备查询条件都写好,然后依照传过来的ID
或然用户名
来剖断鲜明使用哪个..那样的判断逻辑混乱,代码冗长,大家就想找二个方可动态拼接查询条件的方法.

即依据id 恐怕用户名是或不是存在动态的来拼接查询条件.

率先我们需求知道,表明式构成都部队分,表明式是有两部分构成,Parameter和body,第4个是参数,第叁个是抒发式体,表明式体是二进制的位运算,相当于比如(left&right)而left和right要赶回的值必须是主导类型的值,也便是能够出席位运算的值.比方(a,b)=>()那几个lambda表明式中,ab是参数,括号后边中是抒发式体那之中再次来到的值只可以是基本类型.大家要创设叁个表明式树,主要就是创设这几个表明式体,那么那一个表明式体是贰个哪些的花色呢
?BinaryExpression类型,大家只须要结构这几个项目,然后通过Expression.And(left,right)恐怕Expression.Or()那八个方法来协会就可以.
那一个五个法子再次回到值正是BinaryExpression的种类对象.然后大家在用Expression.Lambda<Func<T,bool>>(BinaryExpression,Parameter)那几个主意将那一个表明式树转化为lambda的表明式.这便是其一标题的消除思路,来探视大家是怎么来贯彻的.

首先大家定义了二个表达式变量.

Expression<Func<UserInfo, bool>> where;

爱博体育app,接下来大家初阶张开labmda的布局

接下去,大家来组织参数和供给条件,也是就lambda中的c=>()中的c

爱博体育app 1

ParameterExpression param = Expression.Parameter(typeof(UserInfo), "c");//c=>

            //c=>c.IsDelete==false这里需要不被删除的条件

            MemberExpression left1 = Expression.Property(param, typeof(UserInfo).GetProperty("IsDelete"));构建c.IsDelete

            ConstantExpression right1 = Expression.Constant(false);//构建一个常量 false

            BinaryExpression be = Expression.Equal(left1, right1);构建//c=>c.IsDelete==false 就是现在这个be了

爱博体育app 2

 

上边 大家必要依据大家的标准 也正是id和用户名字符串来承接拼接那么些表明式

率先大家来拼接c.UserId==sid

爱博体育app 3

if (!string.IsNullOrEmpty(Request["sid"]))

            {

                //c.UserId==sid

                int sid = int.Parse(Request["sid"]);

                //根据参数的属性构造左表达式c.UserId

                MemberExpression left2 = Expression.Property(param, typeof(UserInfo).GetProperty("UserId"));

                //构造右表达式sid

                ConstantExpression right2 = Expression.Constant(sid);

                //进行合并:cUserId==sid

                BinaryExpression where2 = Expression.Equal(left2, right2);

                //将这个条件与上一个条件进行与合并:c.IsDelete==false && c.UserId==sid

                be = Expression.And(be, where2);

            }

爱博体育app 4

 

今后大家来拼接第叁个规格

前边大家早已说过,表明式体供给再次来到的是能够做二进制运算的项目,可是那是个值类型字符串,该咋做呢?

在参谋了MSDN中的Expression方法中,开采有如此的多少个方法.Expression.Call().

然后看了示例这个

 

究竟是用来干嘛的??

大家得以用那几个call’方法 ,来调用三个品类
中的一个措施,然后发生三个MethodCallExpression类型的重回值,那样,大家来调用string.
Contains方法不就能够达成我们想要的表明式了么?

且看下边包车型大巴 代码

爱博体育app 5

//c.UserName.Contains(sname)

            if (!string.IsNullOrEmpty(Request["sname"]))

            {

                string sname = Request["sname"];

                MemberExpression left3 = Expression.Property(param, typeof(UserInfo).GetProperty("UserName"));//这里构造c.UserName这个属性表达式.

                ConstantExpression right3 = Expression.Constant(sname);//这里构造sname这个常量表达式

                MethodCallExpression where3 = Expression.Call(left3, typeof(string).GetMethod("Contains"), right3);这里我们用Call这个方法完成/c.UserName.Contains(sname)这个lambda这个表达式的实现.

                be = Expression.And(be, where3);//拼接刚才的be表达式,

            }

where = Expression.Lambda<Func<UserInfo, bool>>(be, param);//生成最后需要的带参数的表达式树.

爱博体育app 6

 

如此那般大家的表明式树拼接就完事了.

关于运行结果就不为大家贴图了,能够运作和lambda的结果同样.足以产生七个尺码的查询.

下边,封装了那么些表达式树的提携类.我们能够参谋.

爱博体育app 7

public class WhereHelper<T>

        where T:class

    {

        private ParameterExpression param;

        private BinaryExpression filter;

        public WhereHelper()

        {

            param = Expression.Parameter(typeof (T), "c");

            //1==1

            Expression left = Expression.Constant(1);

            filter = Expression.Equal(left, left);

        }

        public Expression<Func<T, bool>> GetExpression()

        {

            return Expression.Lambda<Func<T, bool>>(filter,param);

        }

        public void Equal(string propertyName,object value)

        {

            Expression left = Expression.Property(param, typeof (T).GetProperty(propertyName));

            Expression right = Expression.Constant(value, value.GetType());

            Expression result = Expression.Equal(left, right);

            filter = Expression.And(filter, result);

        }

        public void Contains(string propertyName,string value)

        {

            Expression left = Expression.Property(param, typeof (T).GetProperty(propertyName));

            Expression right = Expression.Constant(value, value.GetType());

            Expression result = Expression.Call(left, typeof (string).GetMethod("Contains"), right);

            filter = Expression.And(filter, result);

        }

}

爱博体育app 8

 

当然,那个援救类效能有限,假设有须求者,大家能够团结实行扩张.

正文所涉及的技艺,均为小编师琢磨,因为她斟酌完将来就给我们讲课了规律和实现.俺只是整理出来,给我们做

原文  http://www.cnblogs.com/ruhuaxiao/p/3773596.html

 

 

 

 

Example

上面这段代码体现如何利用表明式树去围绕 IQueryable
数据源构造多个查询并运转。代码生成了多个表明式树来代表查询:

companies.Where(company => (company.ToLower() == "coho winery" || company.Length > 16)).OrderBy(company => company)

在命名空间
[System.Linq.Expressions](https://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions)
下有个厂子方法用来生成二个表明式树来表示这么些查询。表示行业内部查询运算符方法调用的表明式将征引那一个措施的
Queryable
的达成。最后表达式树被传送给 IQueryable 数据源的提供程序的
CreateQuery(Expression)
达成,以创办三个可实行的 IQueryable
类型的询问。通过枚举该查询获得结果。

Expression<Func<string, bool>> expr = name => name.Length > 10 && name.StartsWith("G");
Console.WriteLine(expr);

AndAlsoModifier treeModifier = new AndAlsoModifier();
Expression modifierExpr = treeModifier.Modify(expr);

Console.WriteLine(modifierExpr);

string[] companies = {"Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",
        "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",
        "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",
        "Blue Yonder Airlines", "Trey Research", "The Phone Company",
        "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" };
//转化IQueryable数据源
IQueryable<string> queryableData = companies.AsQueryable();
//编写表示谓词参数的表达式树
ParameterExpression pe = Expression.Parameter(typeof(string), "company");
//新建一个表达式树来表示 'company.ToLower() == "coho winery"' 的表达式
Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
Expression right = Expression.Constant("coho winery", typeof(string));
Expression e1 = Expression.Equal(left, right);
//新建一个表达式树来表示 'company.Length > 16' 表达式
left = Expression.Property(pe, typeof(string).GetProperty("Length"));
right = Expression.Constant(16,typeof(int));
Expression e2 = Expression.GreaterThan(left, right);
//编译表达式树来生成一个表示'(company.ToLower() == "coho winery" || company.Length > 16)' 的表达式
Expression predicateBody = Expression.OrElse(e1, e2);
//新建一个表达式树来表示 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'
MethodCallExpression whereCallExpresstion = Expression.Call(
    typeof(Queryable),
    "Where",
    new Type[] { queryableData.ElementType },
    queryableData.Expression,
    Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));

//排序 OrderBy(company => company)
//新建一个表达式树来表示 'whereCallExpression.OrderBy(company => company)'
MethodCallExpression orderCallExpresstion = Expression.Call(
    typeof(Queryable),
    "OrderBy",
    new Type[] { queryableData.ElementType, queryableData.ElementType },
    whereCallExpresstion,
    Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));

//新建一个可执行的查询表达式树
IQueryable<string> result = queryableData.Provider.CreateQuery<string>(orderCallExpresstion);

//枚举结果
foreach (string company in companies)
    Console.WriteLine(company);

代码中在被传送到 Queryable.Where
方法中,在谓词中利用了一个定位数字。不过,你能够写三个应用程序,来编写翻译在谓词中一个依赖于用户输入的数字变量。你也得以依赖用户的输入,更换查询中调用的正经查询操作符。

怎么利用表达式树生成动态查询

2018-01-11 12:11 by 沉睡的木木夕, 33 阅读, 0 冲突, 收藏编辑

编写翻译代码

  • 始建新的调控台应用程序项目。
  • 增加对 System.Core.dll 的援引(如果未有援引)。
  • 归纳 System.Linq.Expressions 命名空间。
  • 从示例中复制代码,并将其粘贴到 Main 方法中。

[翻译]如何使用表明式树生成动态查询

在LINQ,表明式树常用于结构化查询,目的能源数量完毕了 IQueryable.
比如,LINQ为关系型数据存款和储蓄查询提供了 IQueryable 接口。C#编写翻译器将那一个数据源的查询编写翻译成运营时的表明式树代码。然后查询提供程序可以遍历表达式树数据结构,并转化为方便于数据源的查询语言。

在LINQ中应用表明式树来代表分配给 Expression 类型的Lambda表达式变量。

那节首要陈述了如何使用表明式树创设三个动态LINQ查询。在编写翻译期,动态查询在特别未知的查询的景色下是那个有效的。具体育赛事例,一个应用程序提供了三个用户接口,末了来允许用户钦命叁个或多少个谓词来过滤数据。为了接纳LINQ查询,这种气象应用程序在运作时必须使用表达式树来营造三个LINQ查询。

Example

上边这段代码展示怎么样使用表达式树去围绕 IQueryable 数据源构造七个查询并运转。代码生成了一个表明式树来代表查询:

companies.Where(company => (company.ToLower() == "coho winery" || company.Length > 16)).OrderBy(company => company)

在命名空间 [System.Linq.Expressions](https://docs.microsoft.com/en-us/dotnet/api/system.linq.expressions) 下有个厂子方法用来生成叁个表达式树来表示这么些查询。表示行业内部查询运算符方法调用的表明式将援用那些措施的 Queryable 的达成。最后表达式树被传送给 IQueryable 数据源的提供程序的 CreateQuery(Expression) 达成,以创办一个可奉行的 IQueryable 类型的询问。通过枚举该查询获得结果。

Expression<Func<string, bool>> expr = name => name.Length > 10 && name.StartsWith("G");
Console.WriteLine(expr);

AndAlsoModifier treeModifier = new AndAlsoModifier();
Expression modifierExpr = treeModifier.Modify(expr);

Console.WriteLine(modifierExpr);

string[] companies = {"Consolidated Messenger", "Alpine Ski House", "Southridge Video", "City Power & Light",
        "Coho Winery", "Wide World Importers", "Graphic Design Institute", "Adventure Works",
        "Humongous Insurance", "Woodgrove Bank", "Margie's Travel", "Northwind Traders",
        "Blue Yonder Airlines", "Trey Research", "The Phone Company",
        "Wingtip Toys", "Lucerne Publishing", "Fourth Coffee" };
//转化IQueryable数据源
IQueryable<string> queryableData = companies.AsQueryable();
//编写表示谓词参数的表达式树
ParameterExpression pe = Expression.Parameter(typeof(string), "company");
//新建一个表达式树来表示 'company.ToLower() == "coho winery"' 的表达式
Expression left = Expression.Call(pe, typeof(string).GetMethod("ToLower", Type.EmptyTypes));
Expression right = Expression.Constant("coho winery", typeof(string));
Expression e1 = Expression.Equal(left, right);
//新建一个表达式树来表示 'company.Length > 16' 表达式
left = Expression.Property(pe, typeof(string).GetProperty("Length"));
right = Expression.Constant(16,typeof(int));
Expression e2 = Expression.GreaterThan(left, right);
//编译表达式树来生成一个表示'(company.ToLower() == "coho winery" || company.Length > 16)' 的表达式
Expression predicateBody = Expression.OrElse(e1, e2);
//新建一个表达式树来表示 'queryableData.Where(company => (company.ToLower() == "coho winery" || company.Length > 16))'
MethodCallExpression whereCallExpresstion = Expression.Call(
    typeof(Queryable),
    "Where",
    new Type[] { queryableData.ElementType },
    queryableData.Expression,
    Expression.Lambda<Func<string, bool>>(predicateBody, new ParameterExpression[] { pe }));

//排序 OrderBy(company => company)
//新建一个表达式树来表示 'whereCallExpression.OrderBy(company => company)'
MethodCallExpression orderCallExpresstion = Expression.Call(
    typeof(Queryable),
    "OrderBy",
    new Type[] { queryableData.ElementType, queryableData.ElementType },
    whereCallExpresstion,
    Expression.Lambda<Func<string, string>>(pe, new ParameterExpression[] { pe }));

//新建一个可执行的查询表达式树
IQueryable<string> result = queryableData.Provider.CreateQuery<string>(orderCallExpresstion);

//枚举结果
foreach (string company in companies)
    Console.WriteLine(company);

代码中在被传送到 Queryable.Where 方法中,在谓词中动用了三个恒定数字。不过,你能够写一个应用程序,来编写翻译在谓词中叁个依附于用户输入的数字变量。你也得以依据用户的输入,改变查询中调用的正规化查询操作符。

编译代码

  • 创造新的调整台应用程序项目。
  • 累加对 System.Core.dll 的援引(若无援用)。
  • 包蕴 System.Linq.Expressions 命名空间。
  • 从示例中复制代码,并将其粘贴到 Main 方法中。

愿意有个生活理想的主次人生

相关文章