调用 : 

 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 }