1. 程式人生 > >DataTable擴展:轉化實體ToList

DataTable擴展:轉化實體ToList

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 = new
List<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