利用反射拼接SQL查詢條件字符串


一、應用場景

假設我們有一張數據表Student,並且有以下字段

   public class Student
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public int Grade{ get; set; }
    }

當我們在寫數據訪問層的時候,需要根據Id獲取數據,那我們就很自然的寫一個方法 GetStudentById(int Id);假設需求還需要根據Name來獲取數據,我們也很自然的再寫另一個方法GetStudentByName(string name);此時,項目中,還需要一個根據年紀來查詢數據的方法,或者根據Name和Grade來查詢數據的方法,我們也會新增一個數據訪問層方法或者進行方法重載GetStudent(string name,int Grade);

       而在我們寫的這些方法中,幾乎99%的代碼是相同的,唯一不同的僅僅是Sql語句后的where條件而已,所以,我今天就想,有沒有一種方法,我傳入一個Student對象,方法自己判斷我需要查詢哪些字段呢?當然有,那就是反射了,不過,事后我發現還是有一點點缺陷,文章末尾會說到!

二、"擼"起袖子,打開Visual Studio

    Demo開始前,你需要具備一點點的反射基礎:

1、using System.Reflection;   絕大部分使用的方法在這個命名空間中,有興趣的可以使用Reflector反編譯研究下源碼

2、Type t = object.GetType(); 獲取當前實例的類型描述信息,從而描述信息當中,我們就可以很容易知道當前實例有哪些方法、屬性等等……

3、 PropertyInfo[] infos = t.GetProperties(); 獲取從當前實例得到的描述信息中得到相關的屬性數組,也就是這里可以得到Id,Name,Grade;

三、Demo思路

    數據訪問層的查詢方法,接受一個Student實例參數,在調用該方法前,我們在業務邏輯層中實例化一個Student對象,並根據查詢條件對該實例的屬性進行賦值,比如,我想根據Id等於1的學生信息,那就在實例化對象后,對Id進行賦值即可。

具體思路:

(1)利用反射,獲取條件參數實例中的屬性數組;

(2)遍歷該屬性數組,對當前屬性的值進行判斷,如果為空,則不在查詢條件中,如果不為空,則是業務邏輯層想要的查詢條件;

(3)接上步,如果不為空,則獲取當前屬性的名稱、Value,進行條件的拼接,裝載在集合中;

(4)遍歷完畢,對集合進行join拼接;

        private Student GetStudent(Student stu)
        {
            //獲取當前實例的描述信息
            Type t = stu.GetType();
            //從描述信息當中,獲取當前實例的屬性數組
            PropertyInfo[] infos = t.GetProperties();
            //用於裝載最終的查詢條件的集合
            List<string> list = new List<string>();
            for (int i = 0; i < infos.Length; i++)
            {
                //當前屬性的值不為null,則證明是業務邏輯層中想要的查詢條件
                if (infos[i].GetValue(stu, null) != null)
                {
                    string temp = string.Format("{0}='{1}'", infos[i].Name, infos[i].GetValue(stu, null));
                    list.Add(temp);
                }
            }
            //拼接sql語句
            string s = string.Join("and", list);
            //todo:拼接SQL語句,進行數據庫查詢
            return null;
        }

四、驗證

假如,我想要查詢Id=1並且Name=dotnetgeek的條件的學生記錄,那我們就要在調用數據訪問層方法前,進行初始對象實例化,並且對屬性進行賦值;

Student s = new Student();
s.Id = 1;
s.Name = "dotnetgeek";
 //調用數據訪問層方法
GetStudent(s);

則最終拼接出來的SQL條件則會是如圖所示:(這里只演示到拼接SQL語句的步驟,進行數據查詢不是本文章討論范圍)

五、Bug

    不知道大家有沒有發現到,查詢條件里面出現了一個Bug,請留意我調用方法前是對Id,Name屬性進行賦值的,最終SQL條件里又多了一個Grade屬性,這里因為實體類中,Grade是int類型,是int類型的話就會默認值為0,所以,如果想用這種解決方法的話,還需在判斷為null的地方再判斷不能為0,but,如果用戶想查詢該字段等於0的記錄怎么辦?

六、總結

   這個Demo是我在編碼中浮想出來的,當時我已經寫了2個功能相同的方法,加上同事已經寫過1個相類似的方法,整個數據訪問層中已經出現了相似的三個方法了,假如其他同事又有別的業務需求,是不是要再寫第4個,第5個,第……個呢?所以我就想有沒有一種方法可以實現一下,再說,在Entity Framework中,進行刪除操作也是傳入一個實體模型的,如果有興趣的可以去研究下EF的源碼!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM