天天看點

理想中的SQL語句條件拼接方式背景測試效果

背景

  Orm用過一些,但處理增删改上面做的都不錯。但是查詢上跟我想要的效果總是差了一點。我想要的效果則是這樣,基于某種命名規則進行傳參,背景解析器知道命名規則即可知道它要查詢什麼樣的資料。

  談談我之前的做法,比如說,頁面将查詢條件存入對象,序列化後後傳遞給控制器,此時控制器将其反序列化成Json,資料類型使用Dictionary<string,object>。裡面存儲的Key目前是這樣的格式: BeginTime, EndTime, Age, LikeAddress , NullTel , UnLikeMM , 其中 Begin End Like UnLike Null 等是自定義的命名規則,告訴背景我需要查詢的資料類型,具體的含義看字首大緻即可知道。如傳入BeginTime=2013-10-31 21:55:47,希望得到時間大于這個值的數。

  當時背景則是嘗試去判斷每一個值,如使用 Dictionary.TryGetValue("BeginTime",out obj) , 來進行條件的傳值判斷。這個地方還存在一個類型問題,時間到了背景變成了時間字元串,而不是DateTime類型。此處則需要強制轉換。也正式因為這些原因,代碼寫的不大工整,盡管做了一些封裝,稍微簡潔點,但還不是我要的效果。

  以此為主題,寫了一個初步的實作,希望各位朋友能給出部分建議,如果有類似的成熟的架構,能讓我在背景定義個SQL之後,前端隻要傳入規定的命名字段,即可完成查詢,這樣是再好不過了。

測試效果

var strSql = "select * from Users where ";
            var dic = new Dictionary<string, object>();
            dic["BeginAge"] = "18";//Age>=18
            dic["EndAge"] = 80;//Age<=80
            dic["LikeName"] = "玲";//Name包含'玲'
            dic["IsGirl"] = "true";//IsGirl = true 
            dic["BeginLoginTime"] = DateTime.Now.AddDays(-7);//LoginTime >= 七天前
            dic["EndLoginTime"] = DateTime.Now.ToString();//LoginTime <= 今天
            //部分類型若不正确,則需要手動映射
            SqlMapper mapper = new SqlMapper(dic);
            mapper.LoadTypeMapper<DateTime>("LoginTime");
            mapper.LoadTypeMapper<int>("Age");
            mapper.LoadTypeMapper<bool>("IsGirl");
            //看看生成的條件語句
            var where = mapper.Where();
            Console.WriteLine("{0} {1}", strSql, where);
            Console.WriteLine();      

  

  目前的效果則如圖,得到對應的SQL語句,并且将資料類型轉換正确。

  我們在看看複雜的查詢。

strSql = "select * from Table1 t1 inner join Table2 t2 on t1.ID=t2.Table1ID where ";
            dic["t1.UserName"] = "admin";//UserName='admin'
            dic["t1.BeginAge"] = 18;//Age>=18
            dic["t1.EndAge"] = "80";//Age<=80
            dic["t1.NullSex"] = "false";//Sex is not null
            dic["t1.NullNice"] = "true";//Nice is true
            dic["t2.LikeHomeName"] = "中國";//HomeName like '%中國%'
            dic["t2.UnLikeAddress"] = "郊區";//Address not like '%郊區%'
            dic["t2.BeginCreateTime"] = DateTime.Now.ToString();//CreateTime >= DateTime.Now
            mapper = new SqlMapper(dic);
            mapper.LoadTypeMapper<DateTime>("CreateTime");
            mapper.LoadTypeMapper<int>("Age");
            mapper.LoadTypeMapper<bool>("Sex");
            where = mapper.Where();
            Console.WriteLine("{0} {1}", strSql, where);
            Console.WriteLine();
            //看看格式化後的Dictionary
            foreach (var e in dic)
            {
                Console.WriteLine("{0}:{1}      {2}", e.Key, e.Value, e.Value.GetType());
            }      

    

    我想要的效果,大緻就是這樣,由于是測試代碼,是以直接構造了Dictionary,并且寫入了對應的資料(類型有正确有錯誤)。

    實作方式很簡單,則是周遊Dictionary,根據命名規則定義的字首,來拼接SQL語句,并且檢測目前類型,如果是string類型,則需要和映射的類型比對一下,不相同,則将string類型轉換成Mapper中映射的類型。

    最後在重申一下我想達到的目的,背景定義SQL語句,如Select ....,方法接收Dictionary參數,解析後傳遞給ado或者orm去執行,如此一來,前端想查詢什麼樣的資料,隻需要定義條件就好了。

  測試代碼下載下傳