動態拼接表示式——Expression

姚小丹 發表於 2021-09-14

我們在專案中會遇到以下查詢需求嗎?

比如需要查詢出滿足以下條件的會員:

 條件組一:30-40歲的男性會員

 條件組二:20-30歲的女性會員

 條件組三:60-80歲性別未知的會員

 條件組內是並且關係,但是條件組與組之間是或者關係。 

很多程式設計師腦袋可能會直接蹦出用where拼接條件組的想法,就如同下面圖片所展示的方法 :

動態拼接表示式——Expression

         生成的SQl語句:

動態拼接表示式——Expression 

根據生成的sql語句我們會發現直接使用Where拼接出來的sql語句是並且的關係,

原本我們想要的結果是組與組之間是或者的關係,但是現在變成了並且的關係,很顯然不滿足我們的查詢需求。

想要達到我們的查詢需求,我們得使用動態拼接條件的方法,通常我會使用Expression

動態拼接表示式——Expression

        最終我們生成的sql語句為:

動態拼接表示式——Expression

 從查詢語句可以看出達到了我們的查詢需求,組與組之間是或者的關係。 

 以下是舉例程式碼:

動態拼接表示式——Expression
namespace MyTest
{
    /// <summary>
    /// 動態拼接表示式
    /// </summary>
    public class ExpressionTest : ApplicationService
    {
        public readonly IRepository<CrmMember, int> _memberRep;
        public ExpressionTest(IRepository<CrmMember, int> memberRep)
        {
            _memberRep = memberRep;

        }


        /// <summary>
        /// 使用動態拼接-Expression
        /// </summary>
        [AbpAuthorize]
        public async Task Test()
        {
            #region 描述

            /*         
             *  條件組一:30-40歲的男性會員
             * 條件組二:20-30歲的女性會員
             *  條件組三:60-80歲性別未知的會員
             *  條件組內是並且關係,但是條件組與組之間是或者關係。 
            */
            #endregion

            #region 封裝查詢條件

            var param = new List<SearchMemberInputDto>
            {
                new SearchMemberInputDto { Sex = 1, AgeStart = 30, AgeEnd = 40 },// 30-40歲的男性
                new SearchMemberInputDto { Sex = 2, AgeStart = 20, AgeEnd = 30 }, // 20-30歲的女性
                new SearchMemberInputDto { Sex = 0, AgeStart = 20, AgeEnd = 30 }// 60-80歲性別未知
            };

            #endregion

            #region 動態拼接-Expression

            var members = (await _memberRep.GetAllAsync()).Where(a => a.GroupId == AbpSession.GroupId && a.IsDeleted == false);

            Expression<Func<CrmMember, bool>> expressions = s => false;

            foreach (var item in param)
            {
                expressions = expressions.Or(s => s.Sex == item.Sex && s.Age >= item.AgeStart && s.Age <= item.AgeEnd);
            }

            members = members.Where(expressions);

            var memberList = members.ToList();

            #endregion
        }


        /// <summary>
        /// 測試錯誤的方法
        /// </summary>
        [AbpAuthorize]
        public async Task TestError()
        {
            #region 描述

            /*         
             *  條件組一:30-40歲的男性會員
             * 條件組二:20-30歲的女性會員
             *  條件組三:60-80歲性別未知的會員
             *  條件組內是並且關係,但是條件組與組之間是或者關係。 
             *
             注意:此方法是一個錯誤的寫法 達不到查詢需求
            */

            #endregion

            #region 封裝查詢條件

            var param = new List<SearchMemberInputDto>
            {
                new SearchMemberInputDto { Sex = 1, AgeStart = 30, AgeEnd = 40 },// 30-40歲的男性
                new SearchMemberInputDto { Sex = 2, AgeStart = 20, AgeEnd = 30 }, // 20-30歲的女性
                new SearchMemberInputDto { Sex = 0, AgeStart = 20, AgeEnd = 30 }// 60-80歲性別未知
            };

            #endregion            

            var members = (await _memberRep.GetAllAsync()).Where(a => a.GroupId == AbpSession.GroupId && a.IsDeleted == false);

            foreach (var item in param)
            {
                members = members.Where(s => s.Sex == item.Sex && s.Age >= item.AgeStart && s.Age <= item.AgeEnd);
            }

            var memberList = members.ToList();

        }

    }

    /// <summary>
    /// 條件
    /// </summary>
    public class SearchMemberInputDto
    {

        /// <summary>
        /// 性別
        ///0-未知; 1-男;2-女
        /// </summary>
        public int Sex { get; set; }

        /// <summary>
        /// 年齡-開始值
        /// </summary>
        public int AgeStart { get; set; }

        /// <summary>
        /// 年齡-結束值
        /// </summary>
        public int AgeEnd { get; set; }
    }

}
View Code

 這個是很簡單的一種用法,我這裡只做了簡單的講述,希望對大家有所幫助。