Преобразовать DataTable в список‹T›

У меня есть строго типизированный DataTable типа MyType, я хотел бы преобразовать его в List<MyType>.

Как я могу это сделать ?

Спасибо.


person Kris-I    schedule 15.09.2009    source источник
comment
Вероятно, для преобразования DataTable в Dictionary требуется больше сцен, чем в List.   -  person Vadim    schedule 15.09.2009
comment
DataTable имеет строки и столбцы. Dictionary представляет эту структуру намного лучше, чем List.   -  person Vadim    schedule 15.09.2009
comment
Или, может быть, список словарей. Не могли бы вы предоставить больше информации о том, что вы пытаетесь сделать?   -  person Mike Blandford    schedule 15.09.2009
comment
@Kris-I: Список чего?   -  person Jeff Sternal    schedule 15.09.2009
comment
@Vadim - словарь подходит только в том случае, если в таблице есть уникальный ключ, и вы собираетесь искать значения по этому ключу. В противном случае это накладные расходы, которые вам не нужны. Когда это уместно, вы можете использовать метод Linq .ToDictionary   -  person Keith    schedule 16.09.2009
comment
Преобразование DataTable в общий список в C#   -  person Sen Jacob    schedule 24.10.2012


Ответы (14)


Следующее делает это в одной строке:

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

[Изменить: добавьте ссылку на System.Data.DataSetExtensions в свой проект, если он не компилируется]

person Yuriy Faktorovich    schedule 16.09.2009
comment
Какое здесь значение columnName? - person user123456; 18.07.2013
comment
@CodeMan03 Значение columnName — это имя любого столбца, имеющего его MyType. Если, с другой стороны, каждая строка имеет несколько столбцов, каждый из которых представляет свойство MyType, то ответ Ричарда правильный. - person Yuriy Faktorovich; 13.02.2020

Существуют методы расширения Linq для DataTable.

Добавить ссылку на: System.Data.DataSetExtensions.dll

Затем включите пространство имен: using System.Data.DataSetExtensions

Наконец, вы можете использовать расширения Linq для DataSet и DataTables:

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;
}
person Keith    schedule 15.09.2009
comment
Есть ли простой способ, если вы застряли на .NET 2.0? - person auujay; 15.09.2009
comment
+1 Милаааа! Но что здесь за ключевое слово Convert? Вы имеете в виду Converter? - person MoonKnight; 27.03.2012
comment
@Keith - это должно быть Convert er ‹DataRow, T› . правильный? - person Tohid; 16.01.2013
comment
@Killercam и @Tohid : what is the Convert keyword here? Do you mean Converter? На самом деле он имеет в виду передать func<DataRow, T> conversion , то есть любой delegate/function ожидать datarow, и на выходе будет T сущность .. - person Moumit; 13.12.2013
comment
@auujay - вы можете легко сделать это, используя .net 2.0 .. Вот ссылка .. http://codenicely.blogspot.in/2012/02/converting-your-datatable-into-list.html - person Moumit; 13.12.2013

Таблица данных для списка

    #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 To 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;
    }
person suneelsarraf    schedule 31.12.2011
comment
Выглядит здорово, но как назвать метод? - person pat capozzi; 18.10.2013
comment
Это отличный код!!! Он делает именно то, что мне нужно. Несколько лет, но все еще очень полезно. Спасибо. - person Geert; 07.07.2015
comment
Как вы вызываете метод ConvertTo? - person Megrez7; 30.01.2017

Метод 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();
}

Надеюсь, поможет. С Уважением.

person Gilda    schedule 08.07.2015
comment
Что хорошо в этом, так это то, что ему все равно, есть ли у вашего типа свойства, у которых нет соответствующих столбцов в таблице данных. Спасибо. - person Hugh Seagraves; 10.10.2018

  1. IEnumerable<DataRow> rows = dataTable.AsEnumerable(); (System.Data.DataSetExtensions.dll)
  2. IEnumerable<DataRow> rows = dataTable.Rows.OfType<DataRow>(); (System.Core.dll)
person abatishchev    schedule 14.03.2011

Отлично работает!!

Я сделал несколько обновлений из ответа @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 году.

person zaw    schedule 07.09.2020
comment
Чудесно. Используется как расширение DataTable и работает при первом запуске. - person Alex Alvarez; 09.10.2020

Предполагая, что ваши DataRow наследуются от вашего собственного типа, скажем, MyDataRowType, это должно работать:

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

foreach(DataRow row in dataTable.Rows)
{
    list.Add((MyDataRowType)row);
}

Это предполагает, как вы сказали в комментарии, что вы используете .NET 2.0 и не имеете доступа к методам расширения LINQ.

person Adam Robinson    schedule 15.09.2009
comment
почему бы просто не сделать List‹DataRow› - person Mike Blandford; 15.09.2009
comment
@Mike: Поскольку ОП говорит, что у него есть строго типизированная таблица данных, я предполагаю, что он предпочел бы сохранить эту строгую типизацию в своих результатах. - person Adam Robinson; 15.09.2009

пожалуйста, попробуйте этот код:

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();
}
person Hao    schedule 18.02.2015
comment
Я нашел ваш пример полезным, однако он не работал со свойствами, допускающими значение NULL, поэтому я изменил строку, которая устанавливает значение на pro.SetValue(objT, row[pro.Name] == DBNull.Value ? default(T) : row[pro.Name]); - person Amélie Dupré; 25.02.2020

Создайте список с типом<DataRow>, расширив вызов datatable с помощью AsEnumerable.

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

Ваше здоровье!! Счастливого кодирования

person user2660592    schedule 07.08.2013
comment
DataTable не имеет метода AsEnumerable, если только ваше решение не нуждается в ссылке и использовании для работы. - person johnstaveley; 16.03.2017
comment
Где именно это решение преобразует таблицу данных в Object‹T›? - person John Sheedy; 20.11.2020

спасибо за все сообщения.... Я сделал это с помощью Linq Query, чтобы просмотреть это, перейдите по следующей ссылке

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

person Khalid Rafique    schedule 14.02.2012

Попробуйте этот код, и это самый простой способ преобразовать данные в список

List<DataRow> listtablename = dataTablename.AsEnumerable().ToList();
person Avinash shinde    schedule 13.12.2013
comment
Я получаю эту ошибку; «System.Data.EnumerableRowCollection‹System.Data.DataRow›» не содержит определения для «ToList» и метода расширения «ToList», принимающего первый аргумент типа «System.Data.EnumerableRowCollection‹System.Data.DataRow›» может быть найден (вам не хватает директивы using или ссылки на сборку?) - person Salim; 31.03.2017
comment
теперь разобрался, добавил с помощью System.Linq; - person Salim; 31.03.2017

Существует небольшой пример, который вы можете использовать

            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;
person Ivan Furmanski    schedule 07.12.2017

вы можете преобразовать свой datatable в список. проверьте следующую ссылку

https://stackoverflow.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;
    }
}
person vicky    schedule 03.02.2016

person    schedule
comment
MyType — это объект, который вы бы создали перед кодом, показанным выше, с теми же переменными (ID, Description, Balance) - person Richard YS; 20.10.2016