How do you convert a DataTable into a generic list?

前端 未结 27 2548
后悔当初
后悔当初 2020-11-22 17:04

Currently, I\'m using:

DataTable dt = CreateDataTableInSomeWay();

List list = new List(); 
foreach (DataRow dr in dt.Rows)
{
          


        
相关标签:
27条回答
  • 2020-11-22 17:44

    If you just want a list of values from the "ID" int field returned, you could use...

    List<int> ids = (from row in dt.AsEnumerable() select Convert.ToInt32(row["ID"])).ToList();
    
    0 讨论(0)
  • 2020-11-22 17:44

    I have added some modification to the code from this answer (https://stackoverflow.com/a/24588210/4489664) because for nullable Types it will return exception

    public static List<T> DataTableToList<T>(this DataTable table) where T: new()
    {
        List<T> list = new List<T>();
        var typeProperties = typeof(T).GetProperties().Select(propertyInfo => new
            {
                PropertyInfo = propertyInfo,
                Type = Nullable.GetUnderlyingType(propertyInfo.PropertyType) ?? propertyInfo.PropertyType
            }).ToList();
    
        foreach (var row in table.Rows.Cast<DataRow>())
        {
            T obj = new T();
            foreach (var typeProperty in typeProperties)
            {
                object value = row[typeProperty.PropertyInfo.Name];
                object safeValue = value == null || DBNull.Value.Equals(value)
                    ? null
                    : Convert.ChangeType(value, typeProperty.Type);
    
                typeProperty.PropertyInfo.SetValue(obj, safeValue, null);
            }
            list.Add(obj);
        }
        return list;
    }
    
    0 讨论(0)
  • 2020-11-22 17:45

    You can create a extension function as :

    public static List<T> ToListof<T>(this DataTable dt)
    {
        const BindingFlags flags = BindingFlags.Public | BindingFlags.Instance;
        var columnNames = dt.Columns.Cast<DataColumn>()
            .Select(c => c.ColumnName)
            .ToList();
        var objectProperties = typeof(T).GetProperties(flags);
        var targetList = dt.AsEnumerable().Select(dataRow =>
        {
            var instanceOfT = Activator.CreateInstance<T>();
    
            foreach (var properties in objectProperties.Where(properties => columnNames.Contains(properties.Name) && dataRow[properties.Name] != DBNull.Value))
            {
                properties.SetValue(instanceOfT, dataRow[properties.Name], null);
            }
            return instanceOfT;
        }).ToList();
    
        return targetList;
    }
    
    
    var output = yourDataInstance.ToListof<targetModelType>();
    
    0 讨论(0)
  • 2020-11-22 17:45

    Here's a DataTable extension method that converts a DataTable to a generic list.

    https://gist.github.com/gaui/a0a615029f1327296cf8

    Usage:

    List<Employee> emp = dtTable.DataTableToList<Employee>();
    
    0 讨论(0)
  • 2020-11-22 17:45
    // this is better suited for expensive object creation/initialization
    IEnumerable<Employee> ParseEmployeeTable(DataTable dtEmployees)
    {
        var employees = new ConcurrentBag<Employee>();
    
        Parallel.ForEach(dtEmployees.AsEnumerable(), (dr) =>
        {
            employees.Add(new Employee() 
            {
                _FirstName = dr["FirstName"].ToString(),
                _LastName = dr["Last_Name"].ToString()
            });
        });
    
        return employees;
    }
    
    0 讨论(0)
  • 2020-11-22 17:45

    DataTable.Select() doesnt give the Rows in the order they were present in the datatable.

    If order is important I feel iterating over the datarow collection and forming a List is the right way to go or you could also use overload of DataTable.Select(string filterexpression, string sort).

    But this overload may not handle all the ordering (like order by case ...) that SQL provides.

    0 讨论(0)
提交回复
热议问题