草庐IT

C# DataTable和List之间相互转换

白日梦想家_zery 2023-03-28 原文

 

目录

前言

想法

两者的区别

个人想法

完整代码

方式一

方式二

类型转换


 

前言

最近在捣鼓DataTable,弄到了类型转换,既然弄了,那就整个记录。有不足之处,请多多指教。我看了一下目前的转换方式基本上都大差不差,基本上都是通过反射来操作的。本文介绍的两种方式也都是利用反射来完成的。两种方式都写成的通用类,仅供参考。

想法

两者的区别

  • DataTable 内存中的数据表 一个二维表
  • List<model>泛型数组 这里面存放的是一个一个的被对象化的数据模型

个人想法

  • 其实也可以写一个类,把DataTable转换成 List<Dictionary<string, object>>(),但是并不太建议,我感觉也不太方便。
  • 我比较推荐利用反射来弄,相对通用。
  • 以下方法中的T为自己定义的类,其中的属性需要与数据库对应

完整代码

  • 方式一

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;

namespace GCT.TestInterface
{
    public static class DataTableHelper
    {
        /// <summary>
        /// DataTable转成List
        /// </summary>
        public static List<T> ToDataList<T>(this DataTable dt)
        {
            var list = new List<T>();
            //创建一个属性的列表,并赋值
            var plist = new List<PropertyInfo>(typeof(T).GetProperties());

            if (dt == null || dt.Rows.Count == 0)
            {
                return null;
            }

            foreach (DataRow item in dt.Rows)
            {
                //实例化泛型对象
                T s = Activator.CreateInstance<T>();

                //遍历dataTable中的列集合
                for (int i = 0; i < dt.Columns.Count; i++)
                {
                    //获取属性和DataTable的列名称相同的属性(PropertyInfo)
                    PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
                    //判断是否存在
                    if (info != null)
                    {
                        try
                        {
                            //判断是否为空
                            if (!Convert.IsDBNull(item[i]))
                            {
                                object v = null;
                                //判断属性是否包含可空
                                if (info.PropertyType.ToString().Contains("System.Nullable"))
                                {
                                    //类型转换
                                    v = Convert.ChangeType(item[i], Nullable.GetUnderlyingType(info.PropertyType));
                                }
                                else
                                {
                                    //类型转换
                                    v = Convert.ChangeType(item[i], info.PropertyType);
                                }
                                //赋值
                                info.SetValue(s, v, null);
                            }
                        }
                        catch (Exception ex)
                        {
                            throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
                        }
                    }
                }
                list.Add(s);
            }
            return list;
        }

        /// <summary>
        /// DataTable转成实体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        public static T ToDataEntity<T>(this DataTable dt)
        {
            T s = Activator.CreateInstance<T>();
            if (dt == null || dt.Rows.Count == 0)
            {
                return default(T);
            }
            var plist = new List<PropertyInfo>(typeof(T).GetProperties());
            for (int i = 0; i < dt.Columns.Count; i++)
            {
                PropertyInfo info = plist.Find(p => p.Name == dt.Columns[i].ColumnName);
                if (info != null)
                {
                    try
                    {
                        if (!Convert.IsDBNull(dt.Rows[0][i]))
                        {
                            object v = null;
                            if (info.PropertyType.ToString().Contains("System.Nullable"))
                            {
                                v = Convert.ChangeType(dt.Rows[0][i], Nullable.GetUnderlyingType(info.PropertyType));
                            }
                            else
                            {
                                v = Convert.ChangeType(dt.Rows[0][i], info.PropertyType);
                            }
                            info.SetValue(s, v, null);
                        }
                    }
                    catch (Exception ex)
                    {
                        throw new Exception("字段[" + info.Name + "]转换出错," + ex.Message);
                    }
                }
            }
            return s;
        }

        /// <summary>
        /// List转成DataTable
        /// </summary>
        /// <typeparam name="T">实体类型</typeparam>
        /// <param name="entities">实体集合</param>
        public static DataTable ToDataTable<T>(List<T> entities)
        {
            //判断List的状态
            if (entities == null || entities.Count == 0)
            {
                return null;
            }
            //新建一个DataTable
            var result = new DataTable();
            //获取实体类型数据
            var type = typeof(T);
            //遍历实体类型数据
            foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
            {
                //获取属性类型
                var propertyType = property.PropertyType;
                //判断是否存在,是否可为空
                if (propertyType.IsGenericType && (propertyType.GetGenericTypeDefinition() == typeof(Nullable<>)))
                {
                    propertyType = propertyType.GetGenericArguments()[0];
                }
                //添加列
                result.Columns.Add(property.Name, propertyType);
            }

            foreach (var entity in entities)
            {
                //创建一个具有相同架构的表格行
                DataRow row = result.NewRow();

                foreach (var property in type.GetProperties(BindingFlags.Public | BindingFlags.Instance))
                {
                    //填充数据
                    row[property.Name] = property.GetValue(entity) ?? DBNull.Value;
                }
                //添加行
                result.Rows.Add(row);
            }
            return result;
        }
    }
}
  • 方式二

// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.

using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;

namespace GCT.TestInterface
{
    public static class DataTableHelper
    {
        /// <summary>
        /// 利用反射将Datatable转换为List<T>对象
        /// </summary>
        /// <typeparam name="T">集合</typeparam>
        /// <param name="dt"> datatable对象</param>
        /// <returns></returns>
        public static List<T> ToDataList<T>(this DataTable dt) where T : new()
        {
            //定义集合
            List<T> ts = new List<T>();

            //遍历dataTable中的数据行
            foreach (DataRow dr in dt.Rows)
            {
                T t = new T();
                //这里也有两种写法,可以先获取模型的属性数组,也先遍历再获取指定值的属性,看自己喜好采用
                #region 获得此模型的公共属性
                ////获得此模型的公共属性
                PropertyInfo[] propertys = t.GetType().GetProperties();

                //遍历该对象的所有属性
                foreach (PropertyInfo pi in propertys)
                {
                    string tempName = pi.Name;
                    //检查datatable是否包含此列(列名==对象的属性名)
                    //判断此属性是否有setter,这个啥意思呢,就是我们的实体层的{get;set;}如果我们的实体有了set方法,就说明可以赋值!
                    if (!dt.Columns.Contains(tempName) && !pi.CanWrite) continue;
                    object value = dr[tempName];//取值
                    if (value == DBNull.Value) continue;  //如果非空,则赋给对象的属性
                    pi.SetValue(t, ConvertHelper.HackType(value, pi.PropertyType), null);
                }
                #endregion

                #region 先遍历再获取指定的
                //遍历dataTable列集合
                foreach (var c in dt.Columns)
                {
                    //读取值
                    object value = dr[c.ToString()];
                    //判断是否存在
                    if (value != DBNull.Value)
                    {
                        //获取指定值的属性
                        var p = t.GetType().GetProperty(c.ToString());
                        if (p != null)
                        {
                            //对象赋值
                            p.SetValue(t, ConvertHelper.ChangeType(value, p.PropertyType), null);
                        }
                    }
                }
                #endregion
                //对象添加到泛型集合中
                ts.Add(t);
            }
            return ts;
        }

        /// <summary>
        /// DataTable转成实体对象
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="dt"></param>
        /// <returns></returns>
        /// <exception cref="Exception"></exception>
        public static T ToDataEntity<T>(this DataTable dt) where T : new()
        {
            if (dt.Rows.Count > 1)
            {
                throw new Exception("");
            }
            //遍历行
            foreach (DataRow dr in dt.Rows)
            {
                T t = new T();
                //遍历列
                foreach (var c in dt.Columns)
                {
                    //获取指定值
                    object value = dr[c.ToString()];
                    if (value != DBNull.Value)
                    {
                        //获取公共属性
                        var p = t.GetType().GetProperty(c.ToString());
                        if (p != null)
                        {
                            p.SetValue(t, ConvertHelper.ChangeType(value, p.PropertyType), null);
                        }
                    }
                }
                return t;
            }
            return default(T);
        }
    }
}
  • 类型转换

用方式二有时候会报类型转换的错误,因此也提供了两种转换方式

    /// <summary>
    /// 类型转换
    /// </summary>
    public static class ConvertHelper
    {
        #region 方式一

        public static object HackType(object value, Type conversionType)
        {
            if (conversionType.IsGenericType && conversionType.GetGenericTypeDefinition().Equals(typeof(Nullable<>)))
            {
                if (value == null)
                    return null;
                System.ComponentModel.NullableConverter nullableConverter = new System.ComponentModel.NullableConverter(conversionType);
                conversionType = nullableConverter.UnderlyingType;
            }
            return Convert.ChangeType(value, conversionType);
        }

        #endregion 方式一



        #region 方式二

        public static object ChangeType(object obj, Type conversionType)
        {
            return ChangeType(obj, conversionType, System.Threading.Thread.CurrentThread.CurrentCulture);
        }

        public static object ChangeType(object obj, Type conversionType, IFormatProvider provider)
        {
            #region Nullable

            Type nullableType = Nullable.GetUnderlyingType(conversionType);
            if (nullableType != null)
            {
                if (obj == null)
                {
                    return null;
                }
                return Convert.ChangeType(obj, nullableType, provider);
            }

            #endregion Nullable

            if (typeof(Enum).IsAssignableFrom(conversionType))
            {
                return Enum.Parse(conversionType, obj.ToString());
            }
            return Convert.ChangeType(obj, conversionType, provider);
        }

        #endregion 方式二
    }

有关C# DataTable和List之间相互转换的更多相关文章

  1. ruby-on-rails - 在 Rails 中将文件大小字符串转换为等效千字节 - 2

    我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,

  2. ruby - 使用 ruby​​ 将 HTML 转换为纯文本并维护结构/格式 - 2

    我想将html转换为纯文本。不过,我不想只删除标签,我想智能地保留尽可能多的格式。为插入换行符标签,检测段落并格式化它们等。输入非常简单,通常是格式良好的html(不是整个文档,只是一堆内容,通常没有anchor或图像)。我可以将几个正则表达式放在一起,让我达到80%,但我认为可能有一些现有的解决方案更智能。 最佳答案 首先,不要尝试为此使用正则表达式。很有可能你会想出一个脆弱/脆弱的解决方案,它会随着HTML的变化而崩溃,或者很难管理和维护。您可以使用Nokogiri快速解析HTML并提取文本:require'nokogiri'h

  3. ruby - 将数组的内容转换为 int - 2

    我需要读入一个包含数字列表的文件。此代码读取文件并将其放入二维数组中。现在我需要获取数组中所有数字的平均值,但我需要将数组的内容更改为int。有什么想法可以将to_i方法放在哪里吗?ClassTerraindefinitializefile_name@input=IO.readlines(file_name)#readinfile@size=@input[0].to_i@land=[@size]x=1whilex 最佳答案 只需将数组映射为整数:@land边注如果你想得到一条线的平均值,你可以这样做:values=@input[x]

  4. ruby - 将散列转换为嵌套散列 - 2

    这道题是thisquestion的逆题.给定一个散列,每个键都有一个数组,例如{[:a,:b,:c]=>1,[:a,:b,:d]=>2,[:a,:e]=>3,[:f]=>4,}将其转换为嵌套哈希的最佳方法是什么{:a=>{:b=>{:c=>1,:d=>2},:e=>3,},:f=>4,} 最佳答案 这是一个迭代的解决方案,递归的解决方案留给读者作为练习:defconvert(h={})ret={}h.eachdo|k,v|node=retk[0..-2].each{|x|node[x]||={};node=node[x]}node[

  5. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  6. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  7. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  8. ruby-on-rails - Ruby url 到 html 链接转换 - 2

    我正在使用Rails构建一个简单的聊天应用程序。当用户输入url时,我希望将其输出为html链接(即“url”)。我想知道在Ruby中是否有任何库或众所周知的方法可以做到这一点。如果没有,我有一些不错的正则表达式示例代码可以使用... 最佳答案 查看auto_linkRails提供的辅助方法。这会将所有URL和电子邮件地址变成可点击的链接(htmlanchor标记)。这是文档中的代码示例。auto_link("Gotohttp://www.rubyonrails.organdsayhellotodavid@loudthinking.

  9. ruby-on-rails - 使用 ruby​​ 将多个实例变量转换为散列的更好方法? - 2

    我收到格式为的回复#我需要将其转换为哈希值(针对活跃商家)。目前我正在遍历变量并执行此操作:response.instance_variables.eachdo|r|my_hash.merge!(r.to_s.delete("@").intern=>response.instance_eval(r.to_s.delete("@")))end这有效,它将生成{:first="charlie",:last=>"kelly"},但它似乎有点hacky和不稳定。有更好的方法吗?编辑:我刚刚意识到我可以使用instance_variable_get作为该等式的第二部分,但这仍然是主要问题。

  10. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

随机推荐