59

I have an strongly typed DataTable of type MyType, I'd like convert it in a List<MyType>.

How can I do this ?

Thanks.

David Hoerster
  • 28,421
  • 8
  • 67
  • 102
TheBoubou
  • 19,487
  • 54
  • 148
  • 236
  • 1
    It probably makes more scenes to convert DataTable into Dictionary than List. – Vadim Sep 15 '09 at 14:22
  • DataTable has rows and columns. Dictionary represents this structure much better than List. – Vadim Sep 15 '09 at 14:30
  • Or maybe a list of dictionaries. Could you provide more information on what you're trying to do? – Mike Blandford Sep 15 '09 at 14:32
  • 1
    @Kris-I: a List of what? – Jeff Sternal Sep 15 '09 at 14:40
  • @Vadim - a dictionary is only appropriate if there is a unique key in the table and you're going to look up the values by that key. Otherwise it's overhead that you don't need. When it is appropriate you can use the Linq `.ToDictionary` method – Keith Sep 16 '09 at 08:10
  • [Convert DataTable to Generic List in C#](http://stackoverflow.com/questions/4104464/convert-datatable-to-generic-list-in-c-sharp) – Sen Jacob Oct 24 '12 at 06:09

15 Answers15

58

The following does it in a single line:

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

[Edit: Add a reference to System.Data.DataSetExtensions to your project if this does not compile]

Mitch Wheat
  • 295,962
  • 43
  • 465
  • 541
Yuriy Faktorovich
  • 67,283
  • 14
  • 105
  • 142
  • 25
    What is the columnName value here ? – user123456 Jul 18 '13 at 06:10
  • 1
    @CodeMan03 The value of `columnName` is the name of whatever column has his `MyType`. If on the other hand each row has multiple columns with each representing a property of `MyType` then Richard's answer is right. – Yuriy Faktorovich Feb 12 '20 at 21:11
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()
Richard YS
  • 1,402
  • 15
  • 10
  • MyType is an object that you would create before the code shown above with the same variables (ID, Description, Balance) – Richard YS Oct 20 '16 at 09:14
19

There are Linq extension methods for DataTable.

Add reference to: System.Data.DataSetExtensions.dll

Then include the namespace: using System.Data.DataSetExtensions

Finally you can use Linq extensions on DataSet and DataTables:

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

On .Net 2.0 you can still add generic method:

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;
}
Keith
  • 150,284
  • 78
  • 298
  • 434
  • 1
    Is there an easy way if stuck using .NET 2.0? – auujay Sep 15 '09 at 14:21
  • +1 Sweeeeeet! But what is the `Convert` keyword here? Do you mean `Converter`? – MoonKnight Mar 27 '12 at 13:55
  • @Keith - It has to be Convert **er** . correct? – Tohid Jan 16 '13 at 19:56
  • 1
    @Killercam & @Tohid : `what is the Convert keyword here? Do you mean Converter?` Acually he means to pass a `func conversion` ,which is any `delegate/function` expect a `datarow` and it's out put will be a `T` entity .. – Moumit Dec 13 '13 at 06:41
  • @auujay - you can easily do it using `.net 2.0` .. Here is link .. `http://codenicely.blogspot.in/2012/02/converting-your-datatable-into-list.html` – Moumit Dec 13 '13 at 06:48
11

Data table to List

    #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 collection 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;
    }
suneelsarraf
  • 923
  • 9
  • 7
7

The method ConvertToList that is posted below and uses reflection works perfectly for me. Thanks.

I made a slight modification to make it work with conversions on the T property types.

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();
}

Hope it helps. Regards.

Gilda
  • 81
  • 1
  • 2
  • What's nice about this one is that it doesn't care if your type has properties that don't have matching columns in the datatable. Thanks. – Hugh Seagraves Oct 10 '18 at 20:58
7

That pretty works!!

I made some updates from @suneelsarraf's answer and I removed Convert.ChangeType() because it keeps throwing Invalid Cast Exception. Have a take a look!

#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

And this is how you use in your code.

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

Have Fun! Be Safe in 2020.

zaw
  • 109
  • 1
  • 5
7

I know it a too late

but actually there is a simple way with help of Newtonsoft Json:

var json = JsonConvert.SerializeObject(dataTable);
var YourConvertedDataType = JsonConvert.DeserializeObject<YourDataType>(json);
Ali Amini
  • 356
  • 1
  • 3
  • 12
  • 1
    Great example. I'm testing it against some of the Convert functions in this thread. But even if its slower I get a JSON string out of it. And that could be useful. – dcarl661 Jun 19 '23 at 18:15
  • I always do this too but be aware that JSONConvert always defaults integer values to long and decimal to double. You will have to handle it separately if it creates issues. – Arshya Aug 17 '23 at 04:58
5
  1. IEnumerable<DataRow> rows = dataTable.AsEnumerable(); (System.Data.DataSetExtensions.dll)
  2. IEnumerable<DataRow> rows = dataTable.Rows.OfType<DataRow>(); (System.Core.dll)
abatishchev
  • 98,240
  • 88
  • 296
  • 433
4

Create a list with type<DataRow> by extend the datatable with AsEnumerable call.

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

Cheers!! Happy Coding

Raj Baral
  • 661
  • 6
  • 19
3

please try this code:

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();
}
Nikolay Kostov
  • 16,433
  • 23
  • 85
  • 123
Hao
  • 31
  • 1
  • I found your example useful, however, it didn't work with nullable properties so I changed the line that sets the value to `pro.SetValue(objT, row[pro.Name] == DBNull.Value ? default(T) : row[pro.Name]);` – Amélie Dupré Feb 25 '20 at 17:07
2

Assuming your DataRows inherit from your own type, say MyDataRowType, this should work:

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

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

This is assuming, as you said in a comment, that you're using .NET 2.0 and don't have access to the LINQ extension methods.

Adam Robinson
  • 182,639
  • 35
  • 285
  • 343
1

Try this code and This is easiest way to convert datatable to list

List<DataRow> listtablename = dataTablename.AsEnumerable().ToList();
senthilkumar2185
  • 2,536
  • 3
  • 22
  • 36
  • I'm getting this error; 'System.Data.EnumerableRowCollection' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'System.Data.EnumerableRowCollection' could be found (are you missing a using directive or an assembly reference?) – Sam Salim Mar 31 '17 at 10:08
  • figured out now, added using System.Linq; – Sam Salim Mar 31 '17 at 10:45
1

you can convert your datatable to list. check the following link

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;
    }
}
Community
  • 1
  • 1
vicky
  • 1,546
  • 1
  • 18
  • 35
1

There is a little example that you can use

            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;
1

thanks for all of posts.... I have done it with using Linq Query, to view this please visit the following link

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

Khalid Rafique
  • 161
  • 1
  • 2
  • 13