将DataTable转换为List<T>

59

我有一个强类型的MyType DataTable,我想将其转换为List<MyType>

我该怎么做?

谢谢。


1
将 DataTable 转换为 Dictionary 比 List 更加合理。 - Vadim
DataTable有行和列。相比List,Dictionary更好地表示了这种结构。 - Vadim
或者是一个字典列表。您能否提供更多关于您正在尝试做什么的信息? - Mike Blandford
1
@Kris-I:一个列表是关于什么的? - Jeff Sternal
@Vadim - 字典只有在表中存在唯一键并且您将通过该键查找值时才是合适的。否则,它是您不需要的开销。当合适时,可以使用Linq.ToDictionary方法。 - Keith
将DataTable转换为C#中的泛型列表 - Sen Jacob
15个回答

58
以下代码可以在一行中实现:
dataTable.Rows.OfType<DataRow>()
    .Select(dr => dr.Field<MyType>(columnName)).ToList();

[编辑: 如果编译失败,请在项目中添加对System.Data.DataSetExtensions的引用]


25
这里的columnName值是什么? - user123456
1
@CodeMan03 columnName 的值是具有 MyType 的任何列的名称。另一方面,如果每行都有多个列,每个列代表 MyType 的一个属性,则 Richard 的答案是正确的。 - Yuriy Faktorovich

38
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、Description、Balance)。 - Richard YS

19

有一些用于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;
}

1
如果使用 .NET 2.0 卡住了,有没有简单的方式解决? - auujay
+1 很棒!但这里的 Convert 关键字是什么意思?你是指 Converter 吗? - MoonKnight
@Keith - 必须是 Convert er <DataRow, T> 才对吗? - Tohid
1
@Killercam和@Tohid:这里的Convert关键字是什么意思?你是指Converter吗?实际上,他的意思是传递一个func<DataRow, T> conversion,它是任何期望一个datarow并且输出将是一个T实体的委托/函数。 - Moumit
@auujay - 你可以轻松地使用.net 2.0来完成它。这是链接.. http://codenicely.blogspot.in/2012/02/converting-your-datatable-into-list.html - Moumit

11

将数据表转换为列表

    #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集合转换为DataTable

    #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;
    }

看起来很不错,但是你怎么调用这个方法呢? - pat capozzi
这是一段很棒的代码!!!它完全满足了我的需求。虽然有些年头了,但仍然非常有用。谢谢。 - Geert
你如何调用ConvertTo方法? - Megrez7

7
下面是使用反射的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();
}

希望这能有所帮助。 祝好。


这个很好的地方在于它不关心你的类型是否具有在数据表中没有匹配列的属性。谢谢。 - Hugh Seagraves

7

我知道现在可能有点晚了

但是实际上,有一个简单的方法可以借助Newtonsoft Json来实现:

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

1
很好的例子。我正在对比这个帖子中的一些Convert<T>函数进行测试。即使它速度较慢,我仍然可以得到一个JSON字符串。而且这可能会很有用。 - dcarl661
我也经常这样做,但要注意的是,JSONConvert总是将整数值默认为长整型,将小数默认为双精度浮点型。如果出现问题,你需要单独处理它们。 - Arshya

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年要注意安全。


1
太棒了。作为DataTable的扩展使用,第一次运行就工作正常。 - Alex Alvarez

5
  1. IEnumerable<DataRow> rows = dataTable.AsEnumerable(); (System.Data.DataSetExtensions.dll)
  2. IEnumerable<DataRow> rows = dataTable.Rows.OfType<DataRow>(); (System.Core.dll)
这两条代码均用于将DataTable对象中的行转换成IEnumerable<DataRow>类型的集合,以便于进行数据操作。第一条代码使用了System.Data.DataSetExtensions.dll,而第二条代码则使用了System.Core.dll。

3

请尝试这段代码:

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]); - Amélie Dupré

3
通过使用AsEnumerable函数扩展datatable,可以创建一个类型为<DataRow>的列表。
var mylist = dt.AsEnumerable().ToList();

干杯!愉快地编码


除非您的解决方案需要引用和使用才能工作,否则DataTable没有AsEnumerable方法。 - johnstaveley
这个解决方案确切地将一个datatable转换成Object<T>吗? - John Sheedy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接