最近在做WCF,因为是内部接口,很多地方直接用的弱类型返回(DataSet),这其实是一种非常不好的方式,最近将项目做了修改,将所有接口返回值都修改成强类型,这样可以减少很多与客户端开发人员的沟通,结构内容一目了然
很多时候,后台我们通过ADO.NET使用SQL语句查询出了想要的数据,这时如果直接把这个DataSet丢给客户端开发人员,会让他们一头雾水,并且维护扩展起来都很麻烦,所以想了一个办法,在服务端,首先我们把查询到的数据集转换成泛型集合,再返回给客户端,客户端可以直接使用,也可以再自行转换成自己需要的数据格式,这样做还有一点是因为,DataTable在进行序列化与反序列化时并不那么可靠,记得在多线程同时序列化一个DataTable时会有异常,另外也隐藏了很多小问题,例如需要序列化DataTable的话必须设置TableName等等
首先是封装的辅助类,这个辅助类还可以完善,因为我这里数据库数据类型与实体对象的类型可以直接转换,如果实体类类型与数据库内类型不同,则需要做相应的转换
1 static class Helper 2 { 3 /// <summary> 4 /// DataTable转换成泛型集合 5 /// </summary> 6 /// <typeparam name="T">泛型集合类型</typeparam> 7 /// <param name="dt">DataTable</param> 8 /// <param name="dEnum">字典集合,Key为需要从转换为enum项的DataColumnName,Value为需要转换的枚举的类型</param> 9 /// <returns>以实体类为元素的泛型集合</returns> 10 public static IList<T> DataTableConvertToListGenuric<T>(DataTable dt, Dictionary<string, Type> dEnum) where T : new() 11 { 12 if (dt?.Rows.Count > 0) 13 { 14 // 定义集合 15 List<T> ts = new List<T>(); 16 // 获得此模型的类型 17 Type type = typeof(T); 18 //定义一个临时变量 19 string tempName = string.Empty; 20 //遍历DataTable中所有的数据行 21 foreach (DataRow dr in dt.Rows) 22 { 23 T t = new T(); 24 //如果T是值类型,则先进行装箱 25 object obj = null; 26 if (!t.GetType().IsClass) 27 { 28 obj = t; 29 } 30 //获得此模型的公共属性 31 PropertyInfo[] propertys = t.GetType().GetProperties(); 32 //遍历该对象的所有属性 33 foreach (PropertyInfo pi in propertys) 34 { 35 //将属性名称赋值给临时变量 36 tempName = pi.Name; 37 //检查DataTable是否包含此列(列名==对象的属性名) 38 if (dt.Columns.Contains(tempName)) 39 { 40 // 判断此属性是否有Setter 41 if (!pi.CanWrite) continue;//该属性不可写,直接跳出 42 //取值 43 object value = dr[tempName]; 44 //如果非空,则赋给对象的属性 45 if (value != DBNull.Value) 46 { 47 //如果有枚举项 48 if (dEnum != null) 49 { 50 var queryResult = from n in dEnum 51 where n.Key == tempName 52 select n; 53 //枚举集合中包含与当前属性名相同的项 54 if (queryResult.Count() > 0) 55 { 56 if (obj != null) 57 { 58 //将字符串转换为枚举对象 59 pi.SetValue(obj, Enum.Parse(queryResult.FirstOrDefault().Value, value.ToString()), null); 60 } 61 else 62 { 63 //将字符串转换为枚举对象 64 pi.SetValue(t, Enum.Parse(queryResult.FirstOrDefault().Value, value.ToString()), null); 65 } 66 } 67 else 68 { 69 if (obj != null) 70 { 71 pi.SetValue(obj, value, null); 72 } 73 else 74 { 75 pi.SetValue(t, value, null); 76 } 77 } 78 } 79 else { 80 if (obj != null) 81 { 82 pi.SetValue(obj, value, null); 83 } 84 else 85 { 86 pi.SetValue(t, value, null); 87 } 88 } 89 } 90 } 91 } 92 T ta = default(T); 93 //拆箱 94 if (obj != null) 95 { 96 ta = (T)obj; 97 } 98 else 99 { 100 ta = t; 101 } 102 //对象添加到泛型集合中 103 ts.Add(ta); 104 } 105 return ts; 106 } 107 else 108 { 109 throw new ArgumentNullException("转换的集合为空."); 110 } 111 } 112 113 /// <summary> 114 /// 泛型集合转换成DataTable 115 /// </summary> 116 /// <typeparam name="T">泛型集合类型</typeparam> 117 /// <param name="list">泛型集合对象</param> 118 /// <returns></returns> 119 public static DataTable ListGenuricConvertToDataTable<T>(List<T> list) 120 { 121 if (list?.Count > 0) 122 { 123 Type type = typeof(T); 124 PropertyInfo[] properties = type.GetProperties(); 125 DataTable dt = new DataTable(type.Name); 126 foreach (var item in properties) 127 { 128 dt.Columns.Add(new DataColumn(item.Name) { DataType = item.PropertyType }); 129 } 130 foreach (var item in list) 131 { 132 DataRow row = dt.NewRow(); 133 foreach (var property in properties) 134 { 135 row[property.Name] = property.GetValue(item, null); 136 } 137 dt.Rows.Add(row); 138 } 139 return dt; 140 } 141 else 142 { 143 throw new ArgumentNullException("转换的集合为空."); 144 } 145 } 146 }
下面是测试代码
1 class Program 2 { 3 static void Main(string[] args) 4 { 5 DataTable dt = new DataTable(); 6 dt.Columns.Add("ID", typeof(int)); 7 dt.Columns.Add("Name", typeof(string)); 8 dt.Columns.Add("USex", typeof(string)); 9 dt.Rows.Add(1, "肖潇",Sex.woman); 10 dt.Rows.Add(2, "何峰涛", Sex.man); 11 dt.Rows.Add(3, "王萌", Sex.woman); 12 dt.Rows.Add(4, "汤晓乐", Sex.man); 13 Dictionary<string, Type> dEnum = new Dictionary<string, Type>(); 14 dEnum.Add("USex", typeof(Sex)); 15 List<User> liUser = (List<User>)Helper.DataTableConvertToListGenuric<User>(dt, dEnum); 16 Console.WriteLine("DataTable To List<T>"); 17 foreach (var item in liUser) 18 { 19 Console.WriteLine(item.ID + ":" + item.Name+":"+item.USex); 20 } 21 Console.WriteLine("================"); 22 DataTable dtConvert = Helper.ListGenuricConvertToDataTable(liUser); 23 Console.WriteLine("List<T> To DataTable"); 24 foreach (DataRow item in dtConvert.Rows) 25 { 26 Console.WriteLine(item["ID"] + ":" + item["Name"]+":"+(Sex)item["USex"]); 27 } 28 Console.ReadKey(); 29 } 30 } 31 32 struct User 33 { 34 public int ID { get; set; } 35 public string Name { get; set; } 36 public Sex USex { get; set; } 37 } 38 39 enum Sex { 40 man = 0, 41 woman = 1 42 }