调用 :
1 public ActionResult Index() 2 { 3 DataTable dt = new DataTable(); 4 dt.Columns.Add("Name"); 5 dt.Columns.Add("Age"); 6 dt.Columns.Add("RegisterTime123"); 7 dt.Columns.Add("Last123LoginTime"); 8 dt.Columns.Add("Active"); 9 dt.Rows.Add("zs0", 0, DateTime.Now.AddDays(-0), DateTime.Now, 1); 10 dt.Rows.Add("zs1", 1, DateTime.Now.AddDays(-1), DateTime.Now, 1); 11 dt.Rows.Add("zs2", 2, DateTime.Now.AddDays(-2), DateTime.Now, 1); 12 dt.Rows.Add("zs3", 3, DateTime.Now.AddDays(-3), DateTime.Now, 1); 13 dt.Rows.Add("zs4", 4, DateTime.Now.AddDays(-4), DateTime.Now, 1); 14 List<People> list = new List<People>(); 15 16 //1、 不定义映射时,默认会转换属性名和列名相同的列,属性名和列名不区分大小写 17 list = DataToModelHelper.RefDataTableToList<People>(dt); 18 19 //2、 添加自定义列名和属性名映射 默认列名和属性名相同的也会转换 20 ColumnPropertyMapping[] cmMaps = { 21 new ColumnPropertyMapping("Last123LoginTime","lastLoginTime") 22 ,new ColumnPropertyMapping("RegisterTime123","registerTime") 23 }; 24 list = DataToModelHelper.RefDataTableToList<People>(dt, cmMaps); 25 26 // 27 //3、 DataReader 转换 28 string sql = 29 @" select userid Cuserid, username Cusername, passwordhash Cpasswordhash, 30 email, phonenumber, isfirsttimelogin, accessfailedcount, creationdate, isactive from cicuser "; 31 List<CICUser> list = null; 32 ColumnPropertyMapping[] cpmaps = { 33 new ColumnPropertyMapping("Cuserid", "userid") 34 ,new ColumnPropertyMapping("Cusername", "username") 35 ,new ColumnPropertyMapping("Cpasswordhash", "passwordhash") 36 }; 37 using (IDataReader reader = OHelper.ExecuteReader(sql)) 38 { 39 list = DataToModelHelper.RefDataReaderToList<CICUser>(reader); // 默认匹配和属性名相同的列 40 list = DataToModelHelper.RefDataReaderToList<CICUser>(reader,cpmaps); // 优先匹配自定义映射 41 } 42 43 44 45 return View(); 46 }
测试实体:
1 // 测试的实体类 2 public class People 3 { 4 public string name { get; set; } 5 public int age { get; set; } 6 public DateTime registerTime { get; set; } 7 public DateTime lastLoginTime { get; set; } 8 public int active { get; set; } 9 }
Helper :
1 using System; 2 using System.Collections.Concurrent; 3 using System.Collections.Generic; 4 using System.Data; 5 using System.Linq; 6 using System.Reflection; 7 using System.Text; 8 using System.Threading.Tasks; 9 10 namespace xxoo.Common 11 { 12 13 /** 反射实现DataTable To Model **/ 14 // 实体转换类 15 public class DataToModelHelper 16 { 17 18 private static readonly ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>> TypeProperties = new ConcurrentDictionary<RuntimeTypeHandle, IEnumerable<PropertyInfo>>(); 19 20 private static IEnumerable<PropertyInfo> TypePropertiesCache(Type type) 21 { 22 IEnumerable<PropertyInfo> pis; 23 if (TypeProperties.TryGetValue(type.TypeHandle, out pis)) 24 { 25 return pis; 26 } 27 28 var properties = type.GetProperties(); 29 TypeProperties[type.TypeHandle] = properties; 30 return properties; 31 } 32 33 34 35 /// <summary> 36 /// 通过反射实体属性名称 将DataTable转换实体集 37 /// 列名和属性名称不区分大小写 38 /// </summary> 39 /// <typeparam name="T">需要转换的实体类型</typeparam> 40 /// <param name="ds">查询的数据表</param> 41 /// <param name="parMaps">自定义的实体属性和DataTable列名的映射</param> 42 /// <returns>实体集合</returns> 43 public static List<T> RefDataTableToList<T>(DataTable ds, params ColumnPropertyMapping[] parMaps) where T : new() 44 { 45 46 List<T> list = new List<T>(); 47 if (ds == null || ds.Rows.Count <= 0) 48 return list; // 没有数据 49 50 List<ColumnPropertyConvert<T>> rmmpList = new List<ColumnPropertyConvert<T>>(); //实体列映射集合 51 List<string> columnNameList = new List<string>(); 52 // 循环获取到实体属性 53 foreach (DataColumn item in ds.Columns) 54 { //列名转换为小写 55 columnNameList.Add(item.ColumnName.ToLower()); 56 } 57 58 var type = typeof(T); 59 var allProperties = TypePropertiesCache(type); // 读取缓存属性 60 61 if (parMaps == null || parMaps.Length == 0) 62 { //无自定义映射,默认查找列名和属性名相同的映射 63 foreach (System.Reflection.PropertyInfo proInfo in allProperties) 64 { // 循环实体属性集合 65 if (columnNameList.Contains(proInfo.Name.ToLower())) 66 { //列明中包含该属性名称 67 ColumnPropertyConvert<T> map = new ColumnPropertyConvert<T>(proInfo.Name, proInfo.Name, proInfo); 68 // 判断是否是可空类型 69 if (proInfo.PropertyType.IsGenericType && proInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 70 { 71 map.isNullable = true; 72 } 73 rmmpList.Add(map); 74 } 75 } 76 } 77 else 78 { //有自定义映射,查找默认映射同时 查找自定义映射 79 80 foreach (System.Reflection.PropertyInfo proInfo in allProperties) 81 { // 循环实体属性集合 82 if (columnNameList.Contains(proInfo.Name.ToLower())) 83 { //列明中包含该属性名称 84 ColumnPropertyConvert<T> map = new ColumnPropertyConvert<T>(proInfo.Name, proInfo.Name, proInfo); 85 // 判断是否是可空类型 86 if (proInfo.PropertyType.IsGenericType && proInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 87 { 88 map.isNullable = true; 89 } 90 rmmpList.Add(map); 91 } 92 else 93 { 94 foreach (ColumnPropertyMapping parMap in parMaps) 95 { 96 // 存在该属性 和 该列 97 if (parMap.ProertyName.ToLower() == proInfo.Name.ToLower() && columnNameList.Contains(parMap.ColumnName.ToLower())) 98 { 99 ColumnPropertyConvert<T> map = new ColumnPropertyConvert<T>(parMap.ColumnName, proInfo.Name, proInfo); //列名用反射得到的准确 100 // 判断是否是可空类型 101 if (proInfo.PropertyType.IsGenericType && proInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 102 { 103 map.isNullable = true; 104 } 105 rmmpList.Add(map); 106 } 107 } 108 } 109 } 110 } 111 112 if (rmmpList.Count == 0) return list; // 没有列名和属性名的映射 113 114 // 装载实体数据 115 foreach (DataRow row in ds.Rows) 116 { 117 T t = new T(); 118 foreach (ColumnPropertyConvert<T> map in rmmpList) 119 { 120 try 121 { 122 map.ParseValue(t, map.ProInfo, row[map.ColumnName]); 123 } 124 catch { continue; } 125 } 126 127 list.Add(t); 128 }//foreach datarow 129 return list; 130 } 131 132 133 134 /// <summary> 135 /// 通过反射实体属性名称 将DataTable转换实体集 136 /// 列名和属性名称不区分大小写 137 /// </summary> 138 /// <typeparam name="T">需要转换的实体类型</typeparam> 139 /// <param name="ds">查询的数据表</param> 140 /// <param name="parMaps">自定义的实体属性和DataReader列名的映射</param> 141 /// <returns>实体集合</returns> 142 public static List<T> RefDataReaderToList<T>(IDataReader dr, params ColumnPropertyMapping[] parMaps) where T : new() 143 { 144 145 List<T> list = new List<T>(); 146 if (dr == null) 147 return list; // 没有数据 148 149 List<ColumnPropertyConvert<T>> rmmpList = new List<ColumnPropertyConvert<T>>(); //实体列映射集合 150 List<string> columnNameList = new List<string>(); 151 int fieldCount = dr.FieldCount; 152 for (int i = 0; i < fieldCount; i++) 153 { 154 columnNameList.Add(dr.GetName(i).ToLower()); 155 } 156 157 158 #region 配置实体属性和列名映射 159 var type = typeof(T); 160 var allProperties = TypePropertiesCache(type); // 读取缓存属性 161 162 if (parMaps == null || parMaps.Length == 0) 163 { //无自定义映射,默认查找列名和属性名相同的映射 164 foreach (System.Reflection.PropertyInfo proInfo in allProperties) 165 { // 循环实体属性集合 166 if (columnNameList.Contains(proInfo.Name.ToLower())) 167 { //列明中包含该属性名称 168 ColumnPropertyConvert<T> map = new ColumnPropertyConvert<T>(proInfo.Name, proInfo.Name, proInfo); 169 // 判断是否是可空类型 170 if (proInfo.PropertyType.IsGenericType && proInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 171 map.isNullable = true; 172 rmmpList.Add(map); 173 } 174 } 175 } 176 else 177 { //有自定义映射,查找默认映射同时 查找自定义映射 178 179 foreach (System.Reflection.PropertyInfo proInfo in allProperties) 180 { // 循环实体属性集合 181 if (columnNameList.Contains(proInfo.Name.ToLower())) 182 { //列明中包含该属性名称 183 ColumnPropertyConvert<T> map = new ColumnPropertyConvert<T>(proInfo.Name, proInfo.Name, proInfo); 184 // 判断是否是可空类型 185 if (proInfo.PropertyType.IsGenericType && proInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 186 map.isNullable = true; 187 rmmpList.Add(map); 188 } 189 else 190 { 191 foreach (ColumnPropertyMapping parMap in parMaps) 192 { 193 // 存在该属性 和 该列 194 if (parMap.ProertyName.ToLower() == proInfo.Name.ToLower() && columnNameList.Contains(parMap.ColumnName.ToLower())) 195 { 196 ColumnPropertyConvert<T> map = new ColumnPropertyConvert<T>(parMap.ColumnName, proInfo.Name, proInfo); //列名用反射得到的准确 197 // 判断是否是可空类型 198 if (proInfo.PropertyType.IsGenericType && proInfo.PropertyType.GetGenericTypeDefinition().Equals(typeof(Nullable<>))) 199 map.isNullable = true; 200 rmmpList.Add(map); 201 } 202 } 203 } 204 } 205 } 206 #endregion 207 208 if (rmmpList.Count == 0) return list; // 没有列名和属性名的映射 209 210 // 装载实体数据 211 while (dr.Read()) 212 { 213 T t = new T(); 214 foreach (ColumnPropertyConvert<T> map in rmmpList) 215 { 216 try 217 { 218 map.ParseValue(t, map.ProInfo, dr[map.ColumnName]); 219 } 220 catch { continue; } 221 } 222 223 list.Add(t); 224 } 225 dr.Close(); 226 dr.Dispose(); 227 228 return list; 229 } 230 231 232 } 233 /// <summary> 234 /// 自定义映射类 235 /// </summary> 236 public class ColumnPropertyMapping 237 { 238 /// <summary> 239 /// 列名与实体属性名的映射 240 /// </summary> 241 /// <param name="columnName">列名</param> 242 /// <param name="proertyName">属性名称</param> 243 public ColumnPropertyMapping(string columnName, string proertyName) 244 { 245 this.ColumnName = columnName; 246 this.ProertyName = proertyName; 247 } 248 public string ColumnName { get; set; } 249 public string ProertyName { get; set; } 250 } 251 /// <summary> 252 /// 属性列名数据转换器器 253 /// </summary> 254 /// <typeparam name="T"></typeparam> 255 public class ColumnPropertyConvert<T> where T : new() 256 { 257 public ColumnPropertyConvert(string columnName, string proertyName, System.Reflection.PropertyInfo proInfo) 258 { 259 this.ColumnName = columnName; 260 this.ProertyName = proertyName; 261 this.ProInfo = proInfo; 262 isNullable = false; 263 264 this.ParseValue = (t, m, o) => 265 { 266 267 if (!isNullable) 268 { 269 this.ProInfo.SetValue(t, Convert.ChangeType(o, this.ProInfo.PropertyType), null); 270 } 271 else { // 可空类型 272 this.ProInfo.SetValue(t, Convert.ChangeType(o, Nullable.GetUnderlyingType(m.PropertyType)), null); 273 } 274 }; 275 #region 注释 276 //switch (this.ProInfo.PropertyType.ToString()) 277 //{ 278 // case "System.Int32": 279 // this.ParseValue = (t, m, o) => 280 // { 281 282 // this.ProInfo.SetValue(t, int.Parse(o.ToString()), null); 283 // }; 284 // break; 285 // case "System.Boolean": 286 // this.ParseValue = (t, m, o) => 287 // { 288 // this.ProInfo.SetValue(t, bool.Parse(o.ToString()), null); 289 // }; 290 // break; 291 // case "System.String": 292 // this.ParseValue = (t, m, o) => 293 // { 294 // this.ProInfo.SetValue(t, o.ToString(), null); 295 // }; 296 // break; 297 // case "System.DateTime": 298 // this.ParseValue = (t, m, o) => 299 // { 300 // this.ProInfo.SetValue(t, DateTime.Parse(o.ToString()), null); 301 // }; 302 // break; 303 // case "System.Decimal": 304 // this.ParseValue = (t, m, o) => 305 // { 306 // this.ProInfo.SetValue(t, decimal.Parse(o.ToString()), null); 307 // }; 308 // break; 309 // case "System.Guid": 310 // this.ParseValue = (t, m, o) => 311 // { 312 // this.ProInfo.SetValue(t, Guid.Parse(o.ToString()), null); 313 // }; 314 // break; 315 // default: 316 // break; 317 //}//swicth 318 #endregion 319 } 320 321 public bool isNullable { get; set; } 322 public string ColumnName { get; set; } 323 public string ProertyName { get; set; } 324 public System.Reflection.PropertyInfo ProInfo { get; set; } 325 // "System.Int32":"System.Boolean":"System.String":"System.DateTime":"System.Decimal":"System.Guid": 326 327 public Action<T, System.Reflection.PropertyInfo, object> ParseValue; 328 } 329 }