其實第一次接觸到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表達式樹的最底層架構,
下文再說。