分享一个DataTable转List强类型的类库

类库扩展自Datatable,可以直接用Datatable.ToList<T>()进行转换。为了方便把DataReader装入Datatable,开扩展了一个LoadForReader(this DataTable dt, IDataReader reder),用法很简单。看例子。

复制代码
public override void Execute()
        {
            using (var conn = DbConnection)
            {
                conn.Open();
                MySqlCommand Command = new MySqlCommand(QuerySql, conn);
                var data = new DataTable().LoadForReader(Command.ExecuteReader());
                foreach (var item in data.ToList<Admin>(new List<ConvertMapping> { ConvertMapping.Convert("userId", "Id") }))
                {
                    AddEntityToContext(item);
                }
            }
            SavaChangs();
        }
复制代码

DataTable.ToList<T>()有两个可选参数,第一个是“映射关系集合”,另外一个是“自定义转换器”。下面分别说下有什么作用。

1:映射关系集合

     假设现在数据库一张Student表,Student表拥有Id,StudentName,StudetnAge,同样,我们在项目中有一个Student类,Student类有Id,Name,Age字段。在进行转换的时候,会自动找同名的属性进行映射复制,Id可以进行赋值,但是StudentName和Age却不行。所以我们要把StudentName和Name建立映射关系。

           var mappings = new List<ConvertMapping>{
                    ConvertMapping.Convert("StudentName","Name"),
                    ConvertMapping.Convert("StudentAge","Age")
            };

2:自定义转换器

     假设我们在转换的时候,需要把数据库里面StudentAge字段小于18的在转换的时候全部改成18,就需要用到”自定义转换器”,用法如下:

复制代码
new DataTable().ToList<Admin>(null, (c, r) =>
            {
                if (r["StudentAge"] != DBNull.Value && Convert.ToInt32(r["StudentAge"]) < 18)
                {
                    c.Age = 18;
                }
                else
                {
                    c.Age = Convert.ToInt32(r["StudentAge"]);
                }
            });
复制代码

          下面贴上代码:

复制代码
public static class DatatableExtend
    {
        /// <summary>
        /// 表格转换成List
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="table"></param>
        /// <param name="mappings"></param>
        /// <returns></returns>
        public static List<T> ToList<T>(this DataTable table, IList<ConvertMapping> mappings = null, Action<T, DataRow> convetAc = null) where T : class, new()
        {
            List<T> result = new List<T>();
            if (table == null || table.Rows.Count == 0)
            {
                return result;
            }
            ConvertMapping mappingResult = null;
            foreach (DataRow row in table.Rows)
            {
                T tResult = new T();
                foreach (DataColumn column in table.Columns)
                {
                    if (mappings != null)
                    {
                        mappingResult = mappings.Where(c => c.SourceColumnName.Equals(column.ColumnName, StringComparison.CurrentCultureIgnoreCase)).SingleOrDefault();
                    }
                    if (mappingResult == null)
                    {
                        mappingResult = ConvertMapping.Convert(column.ColumnName, column.ColumnName);
                    }
                    SetPropertyValue(tResult, mappingResult.NewSourceColumnName, row[mappingResult.SourceColumnName].ToString());
                }
                convetAc?.Invoke(tResult, row);
                result.Add(tResult);
            }
            return result;
        }

        public static DataTable LoadForReader(this DataTable dt, IDataReader reder)
        {
            using (reder)
            {
                dt.Load(reder);
            }
            return dt;
        }

        private static void SetPropertyValue<T>(T otype, string propertyName, object value)
        {
            if (otype == null)
            {
                throw new ArgumentNullException(nameof(otype));
            }
            var proInfo = otype.GetType().GetProperty(propertyName, BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase);
            if (proInfo != null)
            {
                if (proInfo.PropertyType == typeof(bool)&&Microsoft.VisualBasic.Information.IsNumeric(value))
                {
                    value = Convert.ToInt32(value);
                }
                proInfo.SetValue(otype, Convert.ChangeType(value, proInfo.PropertyType));
            }
        }
    }

    public class ConvertMapping
    {
        /// <summary>
        /// 源字段
        /// </summary>
        public string SourceColumnName { get; private set; }

        /// <summary>
        /// 新字段
        /// </summary>
        public string NewSourceColumnName { get; private set; }

        private ConvertMapping() { }
        public static ConvertMapping Convert<TType, TNewType>(Expression<Func<TType, string>> sourece, Expression<Func<TNewType, string>> newSource)
        {
            ConvertMapping mapping = new ConvertMapping();
            mapping.SourceColumnName = sourece.Parameters.SingleOrDefault()?.Name;
            mapping.NewSourceColumnName = newSource.Parameters.SingleOrDefault()?.Name;
            return mapping;
        }

        public static ConvertMapping Convert(string sourece, string newSource)
        {
            ConvertMapping mapping = new ConvertMapping();
            mapping.SourceColumnName = sourece;
            mapping.NewSourceColumnName = newSource;
            return mapping;
        }
    }
复制代码
posted @   大壮他哥  阅读(759)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?
点击右上角即可分享
微信分享提示