关于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,第三个是参数,第二个是揭橥式体,表明式体是二进制的位运算,也正是比方(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;

然后大家早先进行labmda的协会

接下去,大家来布局参数和须求条件,也是就lambda中的c=>()中的c

图片 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了

图片 2

 

下边 我们要求依靠大家的尺度 也便是id和用户名字符串来继续拼接这些表明式

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

图片 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);

            }

图片 4

 

至今大家来拼接第一个尺码

日前大家早就说过,表明式体要求回到的是足以做二进制运算的等级次序,然而这是个值类型字符串,该如何是好呢?

在仿照效法了MSDN中的Expression方法中,发掘有那般的二个方法.Expression.Call().

然后看了示例这个

 

究竟是用来干嘛的??

大家能够用那几个call’方法 ,来调用一个类别中的二个措施,然后发生三个MethodCallExpression类型的重返值,那样,大家来调用string.
Contains方法不就足以做到大家想要的表达式了么?

且看下边包车型地铁 代码

图片 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);//生成最后需要的带参数的表达式树.

图片 6

 

与此相类似我们的表明式树拼接就完了了.

有关运维结果就不为大家贴图了,能够运维和lambda的结果一样.得以成功八个条件的查询.

上面,封装了这些表明式树的扶植类.大家能够参谋.

图片 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);

        }

}

图片 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 方法中。

但愿有个生活不错的顺序人生