LINQ为关系型数据存储查询提供了,那样的一个参数可以是lambda表明式

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

在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.兰姆(Lamb)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 方法中。

指望有个生活不错的主次人生

相关文章