C# ORM中反射與泛型的交叉應用 - 動態創建泛型實例併爲其賦值

好久沒有寫文章了,終於找到工作,抽空寫一下冒個泡。

問題

最近遇到一個這樣 ORM 的問題,一個返回類型爲 List 泛型方法中,需要做到根據條件訪問數據庫,並且把得到的結果存入 List 中返回。

由於只是以前學過一段時間的 C#,而且反射一直個人認爲是各中難點,加上泛型,這篇文章純屬個人紀錄,如有錯誤,望各位大佬指正。

分析

根據條件訪問數據庫 ==> 遍歷獲取到的 reader 對象 ==> 創建泛型實例以及泛型 List,並且對實例賦值存入 List ==> 遍歷完成,返回當前的 List

從上面的幾個步驟中我們可以發現,難點就是在於這個泛型實例的創建以及它的屬性賦值。我們可以通過 Activator 的CreateInstance(type) 方法創建,然後通過 type.setValue(object,value,index) 來設置對應的屬性值,至於如何匹配這些屬性值,我們就通過 ORM 中來映射獲取到對應的特性值與數據庫字段的匹配。這樣問題就解決了。

解決方法

這裏分爲幾個步驟,

  1. 獲取到數據庫的返回(ps:這個比較簡單我就不多說了,具體可以直接百度,狗狗都有很多)
  2. 獲取到對應的泛型的類型
    這裏是通過 typeof() 方法
  3. 通過獲取到的類型由 Activator 類的 CreateInstance(type) 方法創建 object 實例
  4. 通過 type 獲取到此實例的屬性列表
  5. 遍歷屬性列表,並與 數據庫 中的屬性對比匹配,得到匹配成功的特性信息。
  6. 判斷特性信息,爲空就跳過,不爲空就通過 setValue(object,value,index) 方法設置屬性的對應值,並添加到 List 中。

代碼

private const string SELECT = "SELECT * FROM dbo.Alvin ";

public static List<TEntity> Query<TEntity>(string condition)
        {
            using (var conn = SqlHelper.Instance.GetConnection())
            {
                var reader = SqlHelper
                   .Instance
                   .ExecuteQuery(conn,
                   SELECT + condition,
                   new List<SqlParameter> {
                   });

                List<TEntity> list = new List<TEntity>();

                //獲取到泛型的類型
                Type type = typeof(TEntity);
                //通過反射由類型創建對應object實例
                object o = Activator.CreateInstance(type);
                //通過類型獲取到有的屬性
                var infos = type.GetProperties();

                while (reader.Read())
                {

                    //Console.WriteLine("infos 數量:{0}",infos.Length);
                    foreach (var info in infos)
                    {
                        //Console.WriteLine("info 不爲空");
                        //獲取到屬性對應的特性信息(這裏就做了匹配)
                        object[] ob = info.GetCustomAttributes(typeof(FieldAttribute), false);
                        if (ob != null)
                        {
                            //通過反射設置對應的屬性值,o代表與o綁定
                            info.SetValue(o, reader[((FieldAttribute)ob[0]).Fields], null);
                            //Console.WriteLine("結果是:{0}", reader[((FieldAttribute)ob[0]).Fields]);
                        }            
                    }
                    //添加到list中
                    list.Add((TEntity)o);
                }
                return list;
            }

        }

這裏 ORM 就不貼上了,這裏 Record 類是完全匹配數據庫裏表段的,但是 RecordLess 是不完全匹配,暫時只測試到這麼多,還有一類就是啥都沒有匹配的還沒測試過,

結果

RecordLess

RecordLess

Record

Record

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章