不管出於什麼原因,有時候框架人員摒棄了NH或EF,而使用原生數據庫訪問對象。
為了優美的編程,用上我寫的輕量級映射擴展方法吧
目的:將SqlDataReader自動轉換成T類型
代碼如下:
public static class SqlDataReaderEx { /// <summary> /// 屬性反射信息緩存 key:類型的hashCode,value屬性信息 /// </summary> private static Dictionary<int, Dictionary<string, PropertyInfo>> propInfoCache = new Dictionary<int, Dictionary<string, PropertyInfo>>(); /// <summary> /// 將SqlDataReader轉成T類型 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="reader"></param> /// <returns></returns> public static T To<T>(this SqlDataReader reader) where T : new() { if (reader == null || reader.HasRows == false) return default(T); var res = new T(); var propInfos = GetFieldnameFromCache<T>(); for (int i = 0; i < reader.FieldCount; i++) { var n = reader.GetName(i).ToLower(); if (propInfos.ContainsKey(n)) { PropertyInfo prop = propInfos[n]; var IsValueType = prop.PropertyType.IsValueType; object defaultValue = null;//引用類型或可空值類型的默認值 if (IsValueType) { if ((!prop.PropertyType.IsGenericType) ||(prop.PropertyType.IsGenericType&&!prop.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))) { defaultValue = 0;//非空值類型的默認值 } } var v = reader.GetValue(i); prop.SetValue(res, (Convert.IsDBNull(v) ? defaultValue : v), null); } } return res; } private static Dictionary<string, PropertyInfo> GetFieldnameFromCache<T>() { Dictionary<string, PropertyInfo> res = null; var hashCode = typeof(T).GetHashCode(); if (!propInfoCache.ContainsKey(hashCode)) { propInfoCache.Add(hashCode, GetFieldname<T>()); } res = propInfoCache[hashCode]; return res; } /// <summary> /// 獲取一個類型的對應數據表的字段信息 /// </summary> /// <typeparam name="T"></typeparam> /// <returns></returns> private static Dictionary<string, PropertyInfo> GetFieldname<T>() { var res = new Dictionary<string, PropertyInfo>(); var props = typeof(T).GetProperties(); foreach (PropertyInfo item in props) { res.Add(item.GetFiledName(), item); } return res; } /// <summary> /// 將SqlDataReader轉成List<T>類型 /// </summary> /// <typeparam name="T"></typeparam> /// <param name="reader"></param> /// <returns></returns> public static List<T> ToList<T>(this SqlDataReader reader) where T : new() { if (reader == null || reader.HasRows == false) return null; var res = new List<T>(); while (reader.Read()) { res.Add(reader.To<T>()); } return res; } /// <summary> /// 獲取該屬性對應到數據表中的字段名稱 /// </summary> /// <param name="propInfo"></param> /// <returns></returns> public static string GetFiledName(this PropertyInfo propInfo) { var fieldname = propInfo.Name; var attr = propInfo.GetCustomAttributes(false); foreach (var a in attr) { if (a is DataFieldAttribute) { fieldname = (a as DataFieldAttribute).Name; break; } } return fieldname.ToLower(); } }
在項目中再也需要reader["fieldname"]這樣的惹人厭的寫法了,如:
換言之,只需要這樣寫:
(x) => { res = x.To<StaffModel>(); }
x是SqlDataReader類型。
基本原理當然少不了反射,實體的屬性可以用DataField特性標記在數據表中的字段名稱,否則與屬性同名,字段名稱不區分大小寫。
DataField特性是自己寫的,只有一個Name屬性。
public class DataFieldAttribute : Attribute { public DataFieldAttribute() { } public DataFieldAttribute(string name) { m_name = name; } private string m_name = null; public string Name { get { return m_name; } set { m_name = value; } } }
是不是很方便,雖然重復造輪子了,但是即使用了原生數據庫訪問對象,又輕松了轉換了實體,帶來的方便性可以彌補一切。
記得點【推薦】