最近一段时间比较闲,看到项目中有一个比较有意思的东西,没错就是C# Expression类,那它能干嘛呢,有兴趣的朋友可以看一下微软官方的文档,https://msdn.microsoft.com/zh-cn/library/system.linq.expressions.expression(v=vs.100).aspx。好了话不多说,直接看案例:
场景:在做后端查询的时候,按照传统的做法我们声明一个查询类,然后再写if判断来拼接各种条件,日后我们页面每添加一个条件,我们需要在逻辑层增加相应判断,这样,我每写一张表的查询,我都需要写一个查询类,有同学可能想到,没关系,我把每个表对应的每个字段都先在底层处理好,日后在前端只需要增加相应的字段了!对没错,要是一个类有10个字段,但只有5个字段是查询字段,或者后面需求又加到6个字段.......做开发的你当然没问题,加一个条件,编译生成DLL,发布,后面业务又要加一个(心想:沃日,你能不能一次说好.....)。说到这里呢,也许你发现好像真是这样的,有没有好的方法解决呢? 接下来,我将跟着你一起思考这个问题。
思考:要是我能在前端直接传来一些条件,根据这些东西我能动态生成Lamda表达式,这样我每添加一个条件只要前端改改,直接上线,发布都免了,那多省事啊。
好的,到这里我们先准备一个实体类,如下:
接下来,我们先看看Expression类的一些基本用法,这里我用代码给大家做演示
string UrL ="https://shop162421329.taobao.com/?spm=a230r.7195193.1997079397.2.H0ME5j"

public partial class User:BaseEntity<Guid> { [Required(ErrorMessage="用户姓名不能为空")] [DisplayName("姓名")] public string UserName { get; set; } [DisplayName("性别")] public Nullable<bool> UserSex { get; set; } [DisplayName("出生日期")] public Nullable<System.DateTime> UserBirthDay { get; set; } public string Phone1 { get; set; } public string Phone2 { get; set; } public string Phone3 { get; set; } string _url; public string Url { get { return "https://shop162421329.taobao.com/?spm=a230r.7195193.1997079397.2.H0ME5j"; } set { _url = value; } } }

public ActionResult Index(User user =null) { var list = userManager.Get(); //创建表达式的开始部分:p=> ParameterExpression parameter1 = Expression.Parameter(typeof(User), "p"); if (!string.IsNullOrEmpty(user.UserName)) { //创建我们要查询的字段:p.UserName MemberExpression para = Expression.Property(parameter1, "UserName"); //给值做转换 ConstantExpression value = Expression.Constant(user.UserName); //创建我们要查询的字段: p.UserName==‘测试1’ var query1 = Expression.Equal(para, value); //创建我们要查询的字段:p.UserName MemberExpression para2 = Expression.Property(parameter1, "Phone1"); //给值做转换 ConstantExpression value2 = Expression.Constant(user.UserName); var query2 = Expression.Equal(para2, value2); var query3 = Expression.Or(query1, query2); //构建like p=>p.UserName.Contains("") Expression like = Expression.Call ( Expression.Property(parameter1, typeof(User).GetProperty("UserName")), //c.DataSourceName typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),// 反射使用.Contains()方法 Expression.Constant(user.UserName) // .Contains(optionName) 不能使用上面组合出来的value ); Expression phone1like = Expression.Call ( Expression.Property(parameter1, typeof(User).GetProperty("Phone1")), //c.DataSourceName typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),// 反射使用.Contains()方法 Expression.Constant("135") // .Contains(optionName) 不能使用上面组合出来的value ); Expression phone2like = Expression.Call ( Expression.Property(parameter1, typeof(User).GetProperty("Phone2")), //c.DataSourceName typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),// 反射使用.Contains()方法 Expression.Constant("135") // .Contains(optionName) 不能使用上面组合出来的value ); Expression phone3like = Expression.Call ( Expression.Property(parameter1, typeof(User).GetProperty("Phone3")), //c.DataSourceName typeof(string).GetMethod("Contains", new Type[] { typeof(string) }),// 反射使用.Contains()方法 Expression.Constant("135") // .Contains(optionName) 不能使用上面组合出来的value ); var query4 = Expression.Or(phone1like, phone2like); var q5 = Expression.Or(query4, phone3like); var q6 = Expression.And(like, q5); var lambda = Expression.Lambda<Func<User, Boolean>>(query1, parameter1); list= list.AsQueryable().Where(lambda).ToList(); } return View(list); }
这样一来,你就明白Expression 的一些基本用法了,但是你可能会问 : "说好的只需要前端改改呢",犹豫项目原因,我后续会继续完善,前端大概格式如下:

var where = []; var v = $("#merchant_accno").val().trim(); if (v!="") { where.push({ Join: "||", Property: "merchant_accno", Operator: "like", Value:v }); }
到这里,我想聪明的你应该明白我接下的通用方法了,感谢以下参考文件
http://www.2cto.com/kf/201305/213949.html;
https://blogs.msdn.microsoft.com/meek/2008/05/02/linq-to-entities-combining-predicates/;
http://blog.csdn.net/hao134838/article/details/51404151;