續上兩篇文章,使用emit構造dynamic method,把 datareader轉換為實體,以避免直接使用反射來實現帶來的效能損失。程式碼看似沒有紕漏,但是實際上我在framwork4下執行時,呼叫 dynamic method時,
系統都會報 “ 找不到方法 ‘?’ ”的錯誤,沒有找到問題所在,網上查了下資料,發現在framwork3.5以上還可以用表示式樹動態構造 執行的語句,並動態編譯成方法。效能上與emit還是接近,,而且程式碼精簡了許多。
廢話不多說,上程式碼
public class EntityConverter { public static Action<T, object> GetSetter<T>(PropertyInfo property) { Action<T, object> result = null; Type type = typeof(T); string key = type.AssemblyQualifiedName + "_set_" + property.Name; if (HttpRuntime.Cache.Get(key) == null) { //建立 對實體 屬性賦值的expression ParameterExpression parameter = Expression.Parameter(type, "t"); ParameterExpression value = Expression.Parameter(typeof(object), "propertyValue"); MethodInfo setter = type.GetMethod("set_" + property.Name); MethodCallExpression call = Expression.Call(parameter, setter, Expression.Convert(value, property.PropertyType)); var lambda = Expression.Lambda<Action<T, object>>(call, parameter, value); result = lambda.Compile(); HttpRuntime.Cache[key] = result; } else { result = HttpRuntime.Cache[key] as Action<T, object>; } return result; } public static List<T> ToList<T>(DataTable dt) where T : new() { List<T> list = new List<T>(); if (dt == null || dt.Rows.Count == 0) { return list; } foreach (DataRow dr in dt.Rows) { T t= new T(); foreach (PropertyInfo prop in typeof(T).GetProperties()) { if (dr.Table.Columns.Contains(prop.Name)) { GetSetter<T>(prop)(t, dr[prop.Name]); } } list.Add(t); } return list; } public static List<T> ToList<T>(IDataReader dr) where T:new() { List<T> list = new List<T>(); while (dr.Read()) { T t = new T(); foreach (PropertyInfo prop in typeof(T).GetProperties()) { GetSetter<T>(prop)(t, dr[prop.Name]); } list.Add(t); } return list; } }
程式碼還稍微有點粗糙,還可以細化一下,比如 datatable和datareader的欄位名稱,和對應實體的屬性名,可以忽略大小寫,目前我的程式碼是區分的,有興趣的可以自己優化。
如果你看完了我寫的文字還程式碼,還是一頭霧水,可以看看我的上兩篇博文。簡單說 就是類似orm的核心功能,把通過ado.net元件查詢到的資料(datatable,datareader)轉換為實體列表 List<T>,
如果你的程式碼框架還比較古老,又不願意引入諸如EF,Nhibernate那樣的比較大的框架,不妨考慮自己寫一個這樣的簡單的方法。
List<T> list;
using (IDataReader dr = sqlCommand.ExecuteReader(sql) { list = EntityConverter.ToList<T>(dr); }