其实第一次接触到ExpressionTree的时候,大概是在四年前,在面试的时候,有人问我,我们有一个前端页面,增加了查询条件,但是却不想变更后台代码,应该怎样处理,苦思冥想很久,想到了如下代码:
1、封装对象
public class OperateObj
{
/// <summary>
/// 条件
/// </summary>
public string Condition { get; set; }
/// <summary>
/// 条件
/// </summary>
public OperateType OperateType { get; set; }
/// <summary>
/// 值
/// </summary>
public string Value { get; set; }
}
public enum OperateType
{
Add=1,
Subtraction=2,
Multiplication=3,
Division=4,
Equal=5
}
2、将所有前台的条件都转换为OperateObj对象,并添加到List数组中,如遇到Name=“张三”这样的条件
则转换为:
List<OperateObj> arrObj = new List<OperateObj>();
arrObj.Add(new OperateObj()
{
Condition = "Name",
OperateType = OperateType.Equal,
Value="张三"
});
将这样的条件映射到后台后,根据这样的数组,重新拼接为Sql语句,
如:原始的Sql语句为:
select * from UserInfo where DepartmentName=“销售部”
根据数组转换为:
select * from UserInfo where DepartmentName=“销售部” and Name=“张三”;
由于是刚毕业时的面试题,尽管回答的牵强,依然获得了一次面试通过的机会,后来我了解到Expression表达式。了解到Expression表达式树之后,才发现之前的回答真的仅仅算是牵强。
一直没有机会总结,因为懒,直到最近在使用MogoDB的再次接触到Expression,同样遇到了拼接条件的问题,在开发的时候,大家一定发现用户在前端查询的条件永远是不确定的,也许一个都不输入,也许是其中某几个查询条件的随机组合。
当然,我们在使用MogoDb时用于使用了.Net中关于MogoDb的插件动态链接库MongoDB.Driver,在这个动态链接库中封装了Expression表达式的查询方式,省了大量的组织MogoDB查询封装的工作。虽然免了直面数据库查询的工作,但依然无法逃避组织查询条件的工作。故,结合之前的学习以及现在的工作,特将Expression表达式树总结一下:
结合自己的也许需求:
我们需要查询这样结构的数据对象:
public class QrCodeItems : BaseEntity
{
/// <summary>
///
/// </summary>
public string EwmCode { get; set; }
/// <summary>
///
/// </summary>
public string Batch { get; set; }
/// <summary>
///
/// </summary>
public string PrizeName { get; set; }
/// <summary>
///
/// </summary>
public int PrizeFlag { get; set; }
/// <summary>
///
/// </summary>
public string FirstUserId { get; set; }
/// <summary>
///
/// </summary>
public DateTime? FirstDate { get; set; }
/// <summary>
///
/// </summary>
public string CurrentUserId { get; set; }
/// <summary>
///
/// </summary>
public DateTime? CurrentDate { get; set; }
/// <summary>
///
/// </summary>
public string DriverId { get; set; }
/// <summary>
///
/// </summary>
public DateTime? DriverScanDate { get; set; }
/// <summary>
/// 0未扫,1已扫,2已兑,3结束
/// </summary>
public int CurrentStage { get; set; }
/// <summary>
/// 码值所属区域
/// </summary>
public string Source { get; set; }
}
所有查询字段都基于该对象,在实际业务中,我们也可以根据数据表结构的字段反射为对象。
ok,我们现在定义最基础的查询条件,Expreesion表达式跟Sql语句一样,我们也会遇到第一个字符串拼接Where 还是拼接And
ParameterExpression param = Expression.Parameter(typeof(QrCodeItems));
Expression filter = null;
Expression left = null;
Expression right = null;
if (!string.IsNullOrWhiteSpace(source))
{
left = Expression.Property(param, "Source");
right = Expression.Constant(source);
filter = Expression.Equal(left, right);
}
//二维码状态
if (!string.IsNullOrWhiteSpace(stage) && stage != "-1")
{
left = Expression.Property(param, "CurrentStage");
right = Expression.Constant(Convert.ToInt32(stage));
filter = Expression.And(filter, Expression.Equal(left, right));
}
我们将所有条件拼接完成之后,转换为Lambda表达式即可:
Expression<Func<QrCodeItems, bool>> where = Expression.Lambda<Func<QrCodeItems, bool>>(filter, param);//生成最后需要的带参数的表达式树.
就这样,我们动态拼接条件的目的就达到了,当然这不是最终代码,我们还可以根据这段代码继续优化,以及我们的目的是探讨Expression表达式树的最底层架构,
下文再说。