Convert DataTable to List<T>
Asked Answered
T

15

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.

Tubbs answered 15/9, 2009 at 14:19 Comment(6)
It probably makes more scenes to convert DataTable into Dictionary than List.Wimple
DataTable has rows and columns. Dictionary represents this structure much better than List.Wimple
Or maybe a list of dictionaries. Could you provide more information on what you're trying to do?Allain
@Kris-I: a List of what?Squat
@Wimple - 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 methodPaquito
Convert DataTable to Generic List in C#Bradberry
B
60

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]

Barnabas answered 16/9, 2009 at 1:38 Comment(2)
What is the columnName value here ?Fourposter
@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.Barnabas
H
40
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()
Hirsch answered 1/9, 2014 at 12:24 Comment(1)
MyType is an object that you would create before the code shown above with the same variables (ID, Description, Balance)Hirsch
P
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;
}
Paquito answered 15/9, 2009 at 14:20 Comment(5)
Is there an easy way if stuck using .NET 2.0?Sidon
+1 Sweeeeeet! But what is the Convert keyword here? Do you mean Converter?Burthen
@Paquito - It has to be Convert er <DataRow, T> . correct?Bystreet
@Killercam & @Bystreet : what is the Convert keyword here? Do you mean Converter? Acually he means to pass a func<DataRow, T> conversion ,which is any delegate/function expect a datarow and it's out put will be a T entity ..Lambart
@Sidon - you can easily do it using .net 2.0 .. Here is link .. http://codenicely.blogspot.in/2012/02/converting-your-datatable-into-list.htmlLambart
G
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;
    }
Gerald answered 31/12, 2011 at 11:8 Comment(3)
Looks great but how do you call the method?Terraterrace
This is a great piece of code!!! It does exactly what I needed. Some years old but still very useful. Thanks.Mold
How do you call ConvertTo method?Levana
K
10

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);
Karlik answered 30/10, 2021 at 11:14 Comment(2)
Great example. I'm testing it against some of the Convert<T> functions in this thread. But even if its slower I get a JSON string out of it. And that could be useful.Blockbuster
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.Subbasement
A
8

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.

Applicative answered 7/9, 2020 at 6:57 Comment(2)
Wonderful. Used as an extension to DataTable and worked the first time I run it.Fillian
This will work if we have predefined object in your case TEntity, but in my case I will receive new DataTable with different column name every time so I don't have any pre-defined TEntity in that case what should I do?Cherie
F
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.

Fidel answered 8/7, 2015 at 7:41 Comment(1)
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.Rives
C
5
  1. IEnumerable<DataRow> rows = dataTable.AsEnumerable(); (System.Data.DataSetExtensions.dll)
  2. IEnumerable<DataRow> rows = dataTable.Rows.OfType<DataRow>(); (System.Core.dll)
Calx answered 14/3, 2011 at 12:9 Comment(0)
L
3

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

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

Cheers!! Happy Coding

Laughton answered 7/8, 2013 at 12:3 Comment(2)
A DataTable does not have an AsEnumerable method unless your solution needs a reference and using to work.Psychic
Where exactly this solution is converting a datatable into Object<T>?Skaggs
C
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();
}
Cogan answered 18/2, 2015 at 14:15 Comment(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]);Lamed
L
1

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.

Landreth answered 15/9, 2009 at 14:24 Comment(2)
why not just make a List<DataRow>Allain
@Mike: Since the OP says he has a strongly-typed DataTable, I would assume he would prefer to keep that strong typing in his results.Landreth
T
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

Teets answered 14/2, 2012 at 8:10 Comment(0)
G
1

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

https://mcmap.net/q/330824/-converting-datatable-to-list

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;
    }
}
Greenockite answered 3/2, 2016 at 7:40 Comment(0)
T
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;
Transposal answered 7/12, 2017 at 16:53 Comment(0)
A
0

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

List<DataRow> listtablename = dataTablename.AsEnumerable().ToList();
Amphora answered 13/12, 2013 at 6:37 Comment(2)
I'm getting this error; 'System.Data.EnumerableRowCollection<System.Data.DataRow>' does not contain a definition for 'ToList' and no extension method 'ToList' accepting a first argument of type 'System.Data.EnumerableRowCollection<System.Data.DataRow>' could be found (are you missing a using directive or an assembly reference?)Whitmore
figured out now, added using System.Linq;Whitmore

© 2022 - 2024 — McMap. All rights reserved.