这就是说这个表明式体是一个什么的档次呢,LINQ为关系型数据存储查询提供了

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

在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.兰姆da<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 类型的兰姆(Lamb)da表明式变量。

这节紧要讲述了什么行使表明式树构建一个动态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 方法中。

指望有个生活能够的次序人生