天天看點

關于ExpressionTree的一點兒想法

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

下文再說。

繼續閱讀