将 DataTable 转换为 List<T>

Posted

技术标签:

【中文标题】将 DataTable 转换为 List<T>【英文标题】:Convert DataTable to List<T> 【发布时间】:2010-11-28 11:42:56 【问题描述】:

我有一个MyType 类型的强类型数据表,我想将其转换为List&lt;MyType&gt;

我该怎么做?

谢谢。

【问题讨论】:

DataTable转Dictionary的场景可能比List多。 DataTable 有行和列。 Dictionary 比 List 更能代表这种结构。 或者字典列表。您能否提供有关您正在尝试做的事情的更多信息? @Kris-I:什么清单? @Vadim - 仅当表中有唯一键并且您将通过该键查找值时,字典才适用。否则,这是您不需要的开销。合适的时候你可以使用 Linq .ToDictionary 方法 【参考方案1】:

以下内容在一行中完成:

dataTable.Rows.OfType<DataRow>()
    .Select(dr => dr.Field<MyType>(columnName)).ToList();

[编辑:如果无法编译,请将System.Data.DataSetExtensions 的引用添加到您的项目中]

【讨论】:

这里的 columnName 值是多少? @CodeMan03 columnName 的值是具有MyType 的任何列的名称。另一方面,如果每一行都有多个列,每列代表MyType 的一个属性,那么理查德的答案是正确的。【参考方案2】:
List<MyType> listName = dataTableName.AsEnumerable().Select(m => new MyType()

   ID = m.Field<string>("ID"),
   Description = m.Field<string>("Description"),
   Balance = m.Field<double>("Balance"),
).ToList()

【讨论】:

MyType 是一个对象,您将在上面显示的代码之前创建一个具有相同变量(ID、描述、余额)的对象【参考方案3】:

DataTable 有 Linq 扩展方法。

添加引用:System.Data.DataSetExtensions.dll

然后包含命名空间:using System.Data.DataSetExtensions

最后你可以在 DataSet 和 DataTables 上使用 Linq 扩展:

var matches = myDataSet.Tables.First().Where(dr=>dr.Field<int>("id") == 1);

在 .Net 2.0 上,您仍然可以添加泛型方法:

public static List<T> ConvertRowsToList<T>( DataTable input, Convert<DataRow, T> conversion) 
    List<T> retval = new List<T>()
    foreach(DataRow dr in input.Rows)
        retval.Add( conversion(dr) );

    return retval;

【讨论】:

如果卡在 .NET 2.0 有没有简单的方法? +1 亲爱的!但是这里的Convert 关键字是什么?你的意思是Converter @Keith - 它必须是 Convert er 。对吗? @Killercam & @Tohid : what is the Convert keyword here? Do you mean Converter? 实际上他的意思是传递一个 func&lt;DataRow, T&gt; conversion ,这是任何 delegate/function 期望一个 datarow 并且它的输出将是一个 T 实体。 . @auujay - 您可以使用.net 2.0 轻松做到这一点.. 这是链接.. http://codenicely.blogspot.in/2012/02/converting-your-datatable-into-list.html【参考方案4】:

数据表到列表

    #region "getobject filled object with property reconized"

    public List<T> ConvertTo<T>(DataTable datatable) where T : new()
    
        List<T> Temp = new List<T>();
        try
        
            List<string> columnsNames = new List<string>();
            foreach (DataColumn DataColumn in datatable.Columns)
                columnsNames.Add(DataColumn.ColumnName);
            Temp = datatable.AsEnumerable().ToList().ConvertAll<T>(row => getObject<T>(row, columnsNames));
            return Temp;
        
        catch
        
            return Temp;
        

    
    public T getObject<T>(DataRow row, List<string> columnsName) where T : new()
    
        T obj = new T();
        try
        
            string columnname = "";
            string value = "";
            PropertyInfo[] Properties;
            Properties = typeof(T).GetProperties();
            foreach (PropertyInfo objProperty in Properties)
            
                columnname = columnsName.Find(name => name.ToLower() == objProperty.Name.ToLower());
                if (!string.IsNullOrEmpty(columnname))
                
                    value = row[columnname].ToString();
                    if (!string.IsNullOrEmpty(value))
                    
                        if (Nullable.GetUnderlyingType(objProperty.PropertyType) != null)
                        
                            value = row[columnname].ToString().Replace("$", "").Replace(",", "");
                            objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(Nullable.GetUnderlyingType(objProperty.PropertyType).ToString())), null);
                        
                        else
                        
                            value = row[columnname].ToString().Replace("%", "");
                            objProperty.SetValue(obj, Convert.ChangeType(value, Type.GetType(objProperty.PropertyType.ToString())), null);
                        
                    
                
            
            return obj;
        
        catch
        
            return obj;
        
    

    #endregion

IEnumerable 集合到数据表

    #region "New DataTable"
    public DataTable ToDataTable<T>(IEnumerable<T> collection)
    
        DataTable newDataTable = new DataTable();
        Type impliedType = typeof(T);
        PropertyInfo[] _propInfo = impliedType.GetProperties();
        foreach (PropertyInfo pi in _propInfo)
            newDataTable.Columns.Add(pi.Name, pi.PropertyType);

        foreach (T item in collection)
        
            DataRow newDataRow = newDataTable.NewRow();
            newDataRow.BeginEdit();
            foreach (PropertyInfo pi in _propInfo)
                newDataRow[pi.Name] = pi.GetValue(item, null);
            newDataRow.EndEdit();
            newDataTable.Rows.Add(newDataRow);
        
        return newDataTable;
    

【讨论】:

看起来不错,但如何调用该方法? 这是一段很棒的代码!!!它完全符合我的需要。有些年头,但仍然非常有用。谢谢。 如何调用 ConvertTo 方法?【参考方案5】:

下面发布的使用反射的方法 ConvertToList 非常适合我。谢谢。

我做了一些修改,使其适用于 T 属性类型的转换。

public List<T> ConvertToList<T>(DataTable dt)

    var columnNames = dt.Columns.Cast<DataColumn>()
            .Select(c => c.ColumnName)
            .ToList();
    var properties = typeof(T).GetProperties();
    return dt.AsEnumerable().Select(row =>
    
        var objT = Activator.CreateInstance<T>();
        foreach (var pro in properties)
        
            if (columnNames.Contains(pro.Name))
            
                 PropertyInfo pI = objT.GetType().GetProperty(pro.Name);
                 pro.SetValue(objT, row[pro.Name] == DBNull.Value ? null : Convert.ChangeType(row[pro.Name], pI.PropertyType));
            
        
        return objT;
   ).ToList();

希望对您有所帮助。 问候。

【讨论】:

这个的好处是它不关心您的类型是否具有在数据表中没有匹配列的属性。谢谢。【参考方案6】:
    IEnumerable&lt;DataRow&gt; rows = dataTable.AsEnumerable(); (System.Data.DataSetExtensions.dll) IEnumerable&lt;DataRow&gt; rows = dataTable.Rows.OfType&lt;DataRow&gt;(); (System.Core.dll)

【讨论】:

【参考方案7】:

这很好用!!

我根据@suneelsarraf 的回答做了一些更新,我删除了Convert.ChangeType(),因为它一直在抛出Invalid Cast Exception。来看看吧!

#region *** Convert DT to List<Object> ***

    private List<I> ConvertTo<I>(DataTable datatable) where I : class
    
        List<I> lstRecord = new List<I>();
        try
        
            List<string> columnsNames = new List<string>();
            foreach (DataColumn DataColumn in datatable.Columns)
                columnsNames.Add(DataColumn.ColumnName);
            lstRecord = datatable.AsEnumerable().ToList().ConvertAll<I>(row => GetObject<I>(row, columnsNames));
            return lstRecord;
        
        catch
        
            return lstRecord;
        

    

    private I GetObject<I>(DataRow row, List<string> columnsName) where I : class
    
        I obj = (I)Activator.CreateInstance(typeof(I));
        try
        
            PropertyInfo[] Properties = typeof(I).GetProperties();
            foreach (PropertyInfo objProperty in Properties)
            
                string columnname = columnsName.Find(name => name.ToLower() == objProperty.Name.ToLower());
                if (!string.IsNullOrEmpty(columnname))
                
                    object dbValue = row[columnname];
                    if (dbValue != DBNull.Value)
                    
                        if (Nullable.GetUnderlyingType(objProperty.PropertyType) != null)
                        
                            objProperty.SetValue(obj, Convert.ChangeType(dbValue, Type.GetType(Nullable.GetUnderlyingType(objProperty.PropertyType).ToString())), null);
                        
                        else
                        
                            objProperty.SetValue(obj, Convert.ChangeType(dbValue, Type.GetType(objProperty.PropertyType.ToString())), null);
                        
                    
                
            
            return obj;
        
        catch(Exception ex)
        
            return obj;
        
    

    #endregion

这就是你在代码中使用的方式。

// Other Codes Here
var lstResult = ConvertTo<TEntity>(dataTableName); // Convert DT to List<TEntity>

玩得开心!在 2020 年保持安全。

【讨论】:

太棒了。用作 DataTable 的扩展,并在我第一次运行时工作。【参考方案8】:

通过使用AsEnumerable 调用扩展datatable,创建一个类型为&lt;DataRow&gt; 的列表。

var mylist = dt.AsEnumerable().ToList();

干杯!!快乐编码

【讨论】:

DataTable 没有 AsEnumerable 方法,除非您的解决方案需要参考和使用才能工作。 这个解决方案究竟在哪里将数据表转换为 Object【参考方案9】:

假设你的DataRows 继承自你自己的类型,比如MyDataRowType,这应该可以工作:

List<MyDataRowType> list = new List<MyDataRowType>();

foreach(DataRow row in dataTable.Rows)

    list.Add((MyDataRowType)row);

正如您在评论中所说,这是假设您使用的是 .NET 2.0 并且无权访问 LINQ 扩展方法。

【讨论】:

为什么不做一个列表 @Mike:既然 OP 说他有一个强类型的 DataTable,我想他更愿意在他的结果中保留这种强类型。【参考方案10】:

请试试这个代码:

public List<T> ConvertToList<T>(DataTable dt)

    var columnNames = dt.Columns.Cast<DataColumn>()
        .Select(c => c.ColumnName)
        .ToList();
    var properties = typeof(T).GetProperties();
    return dt.AsEnumerable().Select(row =>
    
        var objT = Activator.CreateInstance<T>();
        foreach (var pro in properties)
        
            if (columnNames.Contains(pro.Name))
                pro.SetValue(objT, row[pro.Name]);
        
        return objT;
    ).ToList();

【讨论】:

我发现您的示例很有用,但是它不适用于可为空的属性,因此我更改了将值设置为 pro.SetValue(objT, row[pro.Name] == DBNull.Value ? default(T) : row[pro.Name]); 的行【参考方案11】:

感谢所有帖子.... 我已经使用 Linq Query 完成了,要查看此内容,请访问以下链接

http://codenicely.blogspot.com/2012/02/converting-your-datatable-into-list.html

【讨论】:

【参考方案12】:

试试这段代码,这是将数据表转换为列表的最简单方法

List<DataRow> listtablename = dataTablename.AsEnumerable().ToList();

【讨论】:

我收到此错误; “System.Data.EnumerableRowCollection”不包含“ToList”的定义,并且没有扩展方法“ToList”接受“System.Data.EnumerableRowCollection”类型的第一个参数可以找到(您是否缺少 using 指令或程序集引用?) 现在想通了,使用 System.Linq 添加;【参考方案13】:

有一点example可以用

            DataTable dt = GetCustomersDataTable(null);            

            IEnumerable<SelectListItem> lstCustomer = dt.AsEnumerable().Select(x => new SelectListItem()
            
                Value = x.Field<string>("CustomerId"),
                Text = x.Field<string>("CustomerDescription")
            ).ToList();

            return lstCustomer;

【讨论】:

【参考方案14】:

您可以将数据表转换为列表。检查以下链接

https://***.com/a/35171050/1805776

public static class Helper

    public static List<T> DataTableToList<T>(this DataTable dataTable) where T : new()
    
        var dataList = new List<T>();

        //Define what attributes to be read from the class
        const System.Reflection.BindingFlags flags = System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance;

        //Read Attribute Names and Types
        var objFieldNames = typeof(T).GetProperties(flags).Cast<System.Reflection.PropertyInfo>().
            Select(item => new
            
                Name = item.Name,
                Type = Nullable.GetUnderlyingType(item.PropertyType) ?? item.PropertyType
            ).ToList();

        //Read Datatable column names and types
        var dtlFieldNames = dataTable.Columns.Cast<DataColumn>().
            Select(item => new
            
                Name = item.ColumnName,
                Type = item.DataType
            ).ToList();

        foreach (DataRow dataRow in dataTable.AsEnumerable().ToList())
        
            var classObj = new T();

            foreach (var dtField in dtlFieldNames)
            
                System.Reflection.PropertyInfo propertyInfos = classObj.GetType().GetProperty(dtField.Name);

                var field = objFieldNames.Find(x => x.Name == dtField.Name);

                if (field != null)
                

                    if (propertyInfos.PropertyType == typeof(DateTime))
                    
                        propertyInfos.SetValue
                        (classObj, convertToDateTime(dataRow[dtField.Name]), null);
                    
                    else if (propertyInfos.PropertyType == typeof(Nullable<DateTime>))
                    
                        propertyInfos.SetValue
                        (classObj, convertToDateTime(dataRow[dtField.Name]), null);
                    
                    else if (propertyInfos.PropertyType == typeof(int))
                    
                        propertyInfos.SetValue
                        (classObj, ConvertToInt(dataRow[dtField.Name]), null);
                    
                    else if (propertyInfos.PropertyType == typeof(long))
                    
                        propertyInfos.SetValue
                        (classObj, ConvertToLong(dataRow[dtField.Name]), null);
                    
                    else if (propertyInfos.PropertyType == typeof(decimal))
                    
                        propertyInfos.SetValue
                        (classObj, ConvertToDecimal(dataRow[dtField.Name]), null);
                    
                    else if (propertyInfos.PropertyType == typeof(String))
                    
                        if (dataRow[dtField.Name].GetType() == typeof(DateTime))
                        
                            propertyInfos.SetValue
                            (classObj, ConvertToDateString(dataRow[dtField.Name]), null);
                        
                        else
                        
                            propertyInfos.SetValue
                            (classObj, ConvertToString(dataRow[dtField.Name]), null);
                        
                    
                    else
                    

                        propertyInfos.SetValue
                            (classObj, Convert.ChangeType(dataRow[dtField.Name], propertyInfos.PropertyType), null);

                    
                
            
            dataList.Add(classObj);
        
        return dataList;
    

    private static string ConvertToDateString(object date)
    
        if (date == null)
            return string.Empty;

        return date == null ? string.Empty : Convert.ToDateTime(date).ConvertDate();
    

    private static string ConvertToString(object value)
    
        return Convert.ToString(ReturnEmptyIfNull(value));
    

    private static int ConvertToInt(object value)
    
        return Convert.ToInt32(ReturnZeroIfNull(value));
    

    private static long ConvertToLong(object value)
    
        return Convert.ToInt64(ReturnZeroIfNull(value));
    

    private static decimal ConvertToDecimal(object value)
    
        return Convert.ToDecimal(ReturnZeroIfNull(value));
    

    private static DateTime convertToDateTime(object date)
    
        return Convert.ToDateTime(ReturnDateTimeMinIfNull(date));
    

    public static string ConvertDate(this DateTime datetTime, bool excludeHoursAndMinutes = false)
    
        if (datetTime != DateTime.MinValue)
        
            if (excludeHoursAndMinutes)
                return datetTime.ToString("yyyy-MM-dd");
            return datetTime.ToString("yyyy-MM-dd HH:mm:ss.fff");
        
        return null;
    
    public static object ReturnEmptyIfNull(this object value)
    
        if (value == DBNull.Value)
            return string.Empty;
        if (value == null)
            return string.Empty;
        return value;
    
    public static object ReturnZeroIfNull(this object value)
    
        if (value == DBNull.Value)
            return 0;
        if (value == null)
            return 0;
        return value;
    
    public static object ReturnDateTimeMinIfNull(this object value)
    
        if (value == DBNull.Value)
            return DateTime.MinValue;
        if (value == null)
            return DateTime.MinValue;
        return value;
    

【讨论】:

【参考方案15】:

我知道为时已晚

但实际上在 Newtonsoft Json 的帮助下有一个简单的方法:

var json = JsonConvert.SerializeObject(dataTable);
var YourConvertedDataType = JsonConvert.DeserializeObject<YourDataType>(json);

【讨论】:

以上是关于将 DataTable 转换为 List<T>的主要内容,如果未能解决你的问题,请参考以下文章

将list转换为datatable

DataTable转换为List

如何将DataTable转换成List<T>

DataTable转换为其他对象

将list转换为datatable的方法

将 DataTable 转换为 IEnumerable<T>