DataTable扩展:转化实体ToList

直接上代码:

根据属性进行映射: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

 

posted @ 2017-12-24 05:48  二奎  阅读(338)  评论(0编辑  收藏  举报