安使用表达式树生成动态查询。关于Expression表达式树的拼凑。

by admin on 2018年10月5日

[翻译]什么样用表达式树生成动态查询

当LINQ,表达式树常用于结构化查询,目标资源数量实现了
IQueryable.
例如,LINQ也涉嫌项目数码存储查询提供了
IQueryable
接口。C#编译器将这些数据源的询问编译成运行时之表达式树代码。然后查询提供程序可以遍历表达式树数据结构,并转化为适龄于数据源的询问语言。

每当LINQ中运用表达式树来代表分配给
Expression
类型的Lambda表达式变量。

这节主要讲述了怎样使用表达式树构建一个动态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 方法中。

欲来只活理想之次序人生

发表评论

电子邮件地址不会被公开。 必填项已用*标注

网站地图xml地图