C# ORM中反射與泛型的交叉應用
阿新 • • 發佈:2019-01-27
好久沒有寫文章了,終於找到工作,抽空寫一下冒個泡。
問題
最近遇到一個這樣 ORM 的問題,一個返回型別為 List 泛型方法中,需要做到根據條件訪問資料庫,並且把得到的結果存入 List 中返回。
由於只是以前學過一段時間的 C#,而且反射一直個人認為是各中難點,加上泛型,這篇文章純屬個人紀錄,如有錯誤,望各位大佬指正。
分析
根據條件訪問資料庫 ==> 遍歷獲取到的 reader 物件 ==> 建立泛型例項以及泛型 List,並且對例項賦值存入 List ==> 遍歷完成,返回當前的 List
從上面的幾個步驟中我們可以發現,難點就是在於這個泛型例項的建立以及它的屬性賦值。我們可以通過 Activator 的CreateInstance(type) 方法建立,然後通過 type.setValue(object,value,index) 來設定對應的屬性值,至於如何匹配這些屬性值,我們就通過 ORM 中來對映獲取到對應的特性值與資料庫欄位的匹配。這樣問題就解決了。
解決方法
這裡分為幾個步驟,
- 獲取到資料庫的返回(ps:這個比較簡單我就不多說了,具體可以直接百度,狗狗都有很多)
- 獲取到對應的泛型的型別
這裡是通過 typeof() 方法 - 通過獲取到的型別由 Activator 類的 CreateInstance(type) 方法建立 object 例項
- 通過 type 獲取到此例項的屬性列表
- 遍歷屬性列表,並與 資料庫 中的屬性對比匹配,得到匹配成功的特性資訊。
- 判斷特性資訊,為空就跳過,不為空就通過 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;
}
}