最近做項目實現了自動將DataTable對象中的數據轉化為制定Model類型對象列表的功能,這里做記錄:
因為開發過程中往往是要分層的,所以經常要將從數據庫中查詢出來的數據轉變成為對象形式,所以在這里定義了一個ModelConvertor類,用於將從數據庫查詢出來的表形式數據轉化為模型層對象,為了增加通用性,這里使用了泛型,當需要將數據轉化為制定Model列表時,只需要加上泛型參數即可。
首先是定義轉化類 :
1 using System; 2 using System.Collections.Generic; 3 using System.ComponentModel; 4 using System.Data; 5 using System.Linq; 6 using System.Reflection; 7 using System.Text; 8 using System.Threading.Tasks; 9 10 namespace ClassView 11 { 12 /// <summary> 13 /// 進行從 DataTable 或者實現 IDataReader 接口的對象讀取記錄 14 /// 並將結果集轉換為給定類型列表的方法。 15 /// </summary> 16 public class ModelConvetor 17 { 18 /// <summary> 19 /// 從 reader 對象中逐行讀取記錄並將記錄轉化為 T 類型的集合 20 /// </summary> 21 /// <typeparam name="T">目標類型參數</typeparam> 22 /// <param name="reader">實現 IDataReader 接口的對象。</param> 23 /// <returns>指定類型的對象集合。</returns> 24 public static List<T> ConvertToObject<T>(IDataReader reader) 25 where T : class 26 { 27 List<T> list = new List<T>(); 28 T obj = default(T); 29 Type t = typeof(T); 30 Assembly ass = t.Assembly; 31 32 Dictionary<string, PropertyInfo> propertys = ModelConvetor.GetFields<T>(reader); 33 PropertyInfo p = null; 34 if (reader != null) 35 { 36 while (reader.Read()) 37 { 38 obj = ass.CreateInstance(t.FullName) as T; 39 foreach (string key in propertys.Keys) 40 { 41 p = propertys[key]; 42 p.SetValue(obj, ModelConvetor.ChangeType(reader[key], p.PropertyType)); 43 } 44 list.Add(obj); 45 } 46 } 47 48 return list; 49 } 50 51 /// <summary> 52 /// 從 DataTale 對象中逐行讀取記錄並將記錄轉化為 T 類型的集合 53 /// </summary> 54 /// <typeparam name="T">目標類型參數</typeparam> 55 /// <param name="reader">DataTale 對象。</param> 56 /// <returns>指定類型的對象集合。</returns> 57 public static List<T> ConvertToObject<T>(DataTable table) 58 where T : class 59 { 60 return table == null 61 ? new List<T>() 62 : ModelConvetor.ConvertToObject<T>(table.CreateDataReader() as IDataReader); 63 } 64 65 /// <summary> 66 /// 將數據轉化為 type 類型 67 /// </summary> 68 /// <param name="value">要轉化的值</param> 69 /// <param name="type">目標類型</param> 70 /// <returns>轉化為目標類型的 Object 對象</returns> 71 private static object ChangeType(object value, Type type) 72 { 73 if (type.FullName == typeof(string).FullName) 74 { 75 return Convert.ChangeType(Convert.IsDBNull(value) ? null : value, type); 76 } 77 if (type.IsGenericType && type.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 78 { 79 NullableConverter convertor = new NullableConverter(type); 80 return Convert.IsDBNull(value) ? null : convertor.ConvertFrom(value); 81 } 82 return value; 83 } 84 85 /// <summary> 86 /// 獲取reader存在並且在 T 類中包含同名可寫屬性的集合 87 /// </summary> 88 /// <param name="reader"> 89 /// 可寫域的集合 90 /// </param> 91 /// <returns> 92 /// 以屬性名為鍵,PropertyInfo 為值得字典對象 93 /// </returns> 94 private static Dictionary<string, PropertyInfo> GetFields<T>(IDataReader reader) 95 { 96 Dictionary<string, PropertyInfo> result = new Dictionary<string, PropertyInfo>(); 97 int columnCount = reader.FieldCount; 98 Type t = typeof(T); 99 100 PropertyInfo[] properties = t.GetProperties(); 101 if (properties != null) 102 { 103 List<string> readerFields = new List<string>(); 104 for (int i = 0; i < columnCount; i++) 105 { 106 readerFields.Add(reader.GetName(i)); 107 } 108 IEnumerable<PropertyInfo> resList = 109 (from PropertyInfo prop in properties 110 where prop.CanWrite && readerFields.Contains(prop.Name) 111 select prop); 112 113 foreach (PropertyInfo p in resList) 114 { 115 result.Add(p.Name, p); 116 } 117 } 118 return result; 119 } 120 } 121 }
接下來是測試類型:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace ClassView 8 { 9 public class TestObj 10 { 11 public int? UserID { get; set; } 12 public string UserName { get; set; } 13 public decimal? Height { get; set; } 14 public DateTime? Birthday { get; set; } 15 } 16 }
最后是測試代碼:
1 using System; 2 using System.Collections.Generic; 3 using System.Data; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace ClassView 9 { 10 class Program 11 { 12 static void Main(string[] args) 13 { 14 DataTable table = new DataTable(); 15 table.Columns.AddRange(new DataColumn[] 16 { 17 new DataColumn("UserID"), 18 new DataColumn("UserName"), 19 new DataColumn("Height"), 20 new DataColumn("Birthday") 21 }); 22 for (int i = 0; i < 10; i++) 23 { 24 DataRow row = table.NewRow(); 25 row["UserID"] = i % 2 == 0 ? DBNull.Value : i as object; 26 row["UserName"] = "User" + i; 27 row["Height"] = i % 5 == 0 ? DBNull.Value : (i + 5) as object; 28 row["Birthday"] = i % 3 == 0 ? DBNull.Value : (DateTime.Now) as object; 29 table.Rows.Add(row); 30 } 31 List<TestObj> res = ModelConvetor.ConvertToObject<TestObj>(table); 32 foreach (TestObj o in res) 33 { 34 Console.WriteLine(string.Format("UserID:{0}",o.UserID)); 35 Console.WriteLine(string.Format("UserName:{0}", o.UserName)); 36 Console.WriteLine(string.Format("Height:{0}", o.Height)); 37 Console.WriteLine(string.Format("Birthday:{0}", o.Birthday)); 38 Console.WriteLine("-------------------------------------------------------------------------"); 39 } 40 Console.ReadLine(); 41 } 42 } 43 }
執行結果如下:
下次是配置數據庫代碼,to be continue ...