DataTable擴展:轉化實體ToList
阿新 • • 發佈:2017-12-24
nta bnu name 可能 string activator access tree .get
直接上代碼:
根據屬性進行映射:DataTable轉化成實體List
public static class DataTableExtension { public static List<T> ToList<T>(this DataTable dt) { if (dt == null || dt.Rows.Count == 0) { return null; } List<T> entites = newList<T>(); foreach (DataRow dr in dt.Rows) { T t = (T)Activator.CreateInstance(typeof(T)); for (int i = 0; i < dr.Table.Columns.Count; i++) { PropertyInfo propertyInfo = t.GetType().GetProperty(dr.Table.Columns[i].ColumnName);if (propertyInfo != null && dr[i] != DBNull.Value) propertyInfo.SetValue(t, dr[i], null); } entites.Add(t); } return entites; } } }
但是需求往往沒有這麽簡單,如果屬性名稱和列名不一致,如列名是excel導入過來的,就很有可能是漢字。
我的解決辦法就是,在實體模型中,添加Attribute,來註明每個屬性和列名的對應關系,如下:
public class Bill { [Column("序號")] public int Id { get; set; } [Column("姓名")] public string PatientName { get; set; } [Column("結算日期")] public DateTime BillDate { get; set; } }
現在有兩種映射方式了,為了使代碼不要太難看,只能重構一下:
public static class DataTableExtension { public static List<T> ToList<T>(this DataTable dt, IRowMapper<T> rowMapper) { if (dt == null || dt.Rows.Count == 0) { return null; } List<T> entites = new List<T>(); foreach (DataRow dr in dt.Rows) { var t = rowMapper.MapRow(dr); entites.Add(t); } return entites; } }
添加了一個接口IRowMapper,表明是屬性映射,還是自定義的映射。
來看下自定義映射具體的實現:
public class ColumnAttributeMapper<T> : IRowMapper<T> { private static Dictionary<string, Dictionary<string, string>> ColumnPropertyMapper= new Dictionary<string, Dictionary<string, string>>(); public ColumnAttributeMapper() { if (!ColumnPropertyMapper.ContainsKey(typeof(T).Name)) { Dictionary<string, string> dict = new Dictionary<string, string>(); var props = typeof(T).GetProperties(); foreach (var prop in props) { var attribute = prop.GetCustomAttributes(true).OfType<ColumnAttribute>().FirstOrDefault(); dict.Add(attribute.Name, prop.Name); } ColumnPropertyMapper.Add(typeof(T).Name, dict); } } public T MapRow(DataRow dr) { T t = (T)Activator.CreateInstance(typeof(T)); for (int i = 0; i < dr.Table.Columns.Count; i++) { if (ColumnPropertyMapper.ContainsKey(t.GetType().Name)) { var dict = ColumnPropertyMapper[t.GetType().Name]; var property = dict[dr.Table.Columns[i].ColumnName]; PropertyInfo propertyInfo = t.GetType().GetProperty(property); if (propertyInfo != null && dr[i] != DBNull.Value) propertyInfo.SetValue(t, dr[i], null); } } return t; } }
在構造函數中定義了一個靜態的字典,用於存儲實體中列名和屬性名的對應關系(這裏有點繞,我還沒想到更好的方法!),
具體調用方法:
public static void TestPropertyMapper() { DataTable dt = new DataTable(); dt.Columns.Add("Id", typeof(int)); dt.Columns.Add("PatientName", typeof(string)); dt.Columns.Add("BillDate", typeof(DateTime)); dt.Rows.Add(1, "HKK", DateTime.Now); dt.Rows.Add(2, "WQ", DateTime.Now); dt.Rows.Add(3, "HS", DateTime.Now); List<Bill> bills = dt.ToList<Bill>(rowMapper: new PropertyColumnMapper<Bill>()); } private static void TestColumnMapper() { DataTable dt = new DataTable(); dt.Columns.Add("序號", typeof(int)); dt.Columns.Add("姓名", typeof(string)); dt.Columns.Add("結算日期", typeof(DateTime)); dt.Rows.Add(1, "HKK", DateTime.Now); dt.Rows.Add(2, "WQ", DateTime.Now); dt.Rows.Add(3, "HS", DateTime.Now); List<Bill> bills = dt.ToList<Bill>(rowMapper: new ColumnAttributeMapper<Bill>()); }
代碼上傳到github:https://github.com/hankuikuide/ExcelAccessor/tree/master/Han.DataAccess
DataTable擴展:轉化實體ToList