关于Expression表明式树的拼接爱博体育app,怎么着利用表达式树生成动态查询

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

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

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

那节主要讲述了何等利用表明式树创设二个动态LINQ查询。在编写翻译期,动态查询在特殊未知的询问的气象下是相当有效的。具体育赛事例,2个应用程序提供了1个用户接口,最后来允许用户内定3个或七个谓词来过滤数据。为了利用LINQ查询,那种气象应用程序在运营时务必选用表明式树来构建二个LINQ查询。

关于Expression表明式树的拼接

 

前不久在做项目中相见二个题材,须求是那般的:

我要对曾经存在的用户实行搜索,能够依照用户的id
恐怕用户名当中的一有个别字符来搜寻出来,那样就应运而生了两种状态
唯有id,只有用户名中一部字符,或许全体都有.

大家用的MVC+EF5.0的框架,在BLL层进行询问的
时候要求创设lambda表明式来作为查询条件,然而,大家怎么来构建lambda来规定询问的规格吧?大家知道Express<Func<T,bool>>那样的四个参数能够是lambda表明式,不过此间的按标准拼接式无法采纳委托链的方式的.当然还有一种消除办法,作者把全部查询条件都写好,然后根据传过来的ID
或然用户名
来判定显明使用哪个..那样的判断逻辑混乱,代码冗长,我们就想找3个得以动态拼接查询条件的方法.

即依照id 或然用户名是还是不是留存动态的来拼接查询条件.

率先我们须要领会,表明式构成都部队分,表达式是有两局地组成,Parameter和body,第一个是参数,第二个是表述式体,表明式体是二进制的位运算,也便是比如(left&right)而left和right要回来的值必须是基本类型的值,也正是足以涉足位运算的值.例如(a,b)=>()那么些lambda表明式中,ab是参数,括号后边中是表述式体那中间重临的值只可以是基本类型.咱们要创设1个表明式树,主要便是创设这一个表达式体,那么这一个表明式体是一个什么的体系呢
?BinaryExpression类型,大家只必要组织那么些项目,然后通过Expression.And(left,right)恐怕Expression.Or()那七个点子来布局即可.
那几个多个主意重回值便是BinaryExpression的项目对象.然后我们在用Expression.Lambda<Func<T,bool>>(BinaryExpression,Parameter)这些措施将这一个表达式树转化为lambda的发挥式.那正是以此难题的
化解思路,来看看大家是怎么来完毕的.

第叁大家定义了1个表明式变量.

Expression<Func<UserInfo, bool>> where;

然后大家开始举行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方法中,发现有如此的2个方法.Expression.Call().

然后看了示例这个

 

究竟是用来干嘛的??

我们得以用这一个call’方法 ,来调用一个品种
中的三个主意,然后产生3个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
方法中,在谓词中运用了1个永恒数字。可是,你能够写三个应用程序,来编写翻译在谓词中三个借助于用户输入的数字变量。你也得以依据用户的输入,更改查询中调用的标准查询操作符。

什么使用表明式树生成动态查询

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

编写翻译代码

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

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

在LINQ,表明式树常用于结构化查询,指标能源数量完成了 IQueryable.
例如,LINQ为关系型数据存款和储蓄查询提供了 IQueryable 接口。C#编写翻译器将那些数据源的询问编译成运维时的表明式树代码。然后查询提供程序能够遍历表明式树数据结构,并转账为适龄于数据源的询问语言。

在LINQ中央银行使表明式树来代表分配给 Expression 类型的Lambda表达式变量。

那节主要讲述了哪些行使表明式树创设贰个动态LINQ查询。在编写翻译期,动态查询在特种未知的查询的情状下是相当有效的。具体育赛事例,3个应用程序提供了一个用户接口,最终来允许用户钦点2个或四个谓词来过滤数据。为了利用LINQ查询,那种景况应用程序在运作时务必使用表明式树来营造三个LINQ查询。

Example

上面那段代码显示什么使用表明式树去围绕 IQueryable 数据源构造八个询问并运转。代码生成了3个表明式树来表示查询:

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 方法中,在谓词中运用了四个固定数字。不过,你能够写一个应用程序,来编写翻译在谓词中1个凭借于用户输入的数字变量。你也能够依照用户的输入,更改查询中调用的专业查询操作符。

编写翻译代码

  • 创设新的控制台应用程序项目。
  • 增进对 System.Core.dll 的引用(假诺没有引用)。
  • 回顾 System.Linq.Expressions 命名空间。
  • 从示例中复制代码,并将其粘贴到 Main 方法中。

企望有个生活不错的先后人生

相关文章