Convert DataTable to Generic List in C#

后端 未结 9 1242
既然无缘
既然无缘 2020-12-01 01:28

Disclaimer: I know its asked at so many places at SO.
My query is a little different.

Coding Language: C# 3.5

I have a DataTable named cardsTable that

相关标签:
9条回答
  • 2020-12-01 02:04

    Just a little simplification. I don't use ItemArray:

    List<Person> list = tbl.AsEnumerable().Select(x => new Person
                        {
                            Id = (Int32) (x["Id"]),
                            Name = (string) (x["Name"] ?? ""),
                            LastName = (string) (x["LastName"] ?? "")
                        }).ToList();
    
    0 讨论(0)
  • 2020-12-01 02:11

    You can map Data Table to model class using a Generic class like below.

    Generic class

     public static class DataTableMappingtoModel
        {
            /// <summary>
            /// Maps Data Table values to coresponded model propertise
            /// </summary>
            /// <typeparam name="T"></typeparam>
            /// <param name="dt"></param>
            /// <returns></returns>
            public static List<T> MappingToEntity<T>(this DataTable dt) 
            {
                try
                {
                    var lst = new List<T>();
                    var tClass = typeof (T);
                    PropertyInfo[] proInModel = tClass.GetProperties();
                    List<DataColumn> proInDataColumns = dt.Columns.Cast<DataColumn>().ToList();
                    T cn;
                    foreach (DataRow item in dt.Rows)
                    {
                        cn = (T) Activator.CreateInstance(tClass);
                        foreach (var pc in proInModel)
                        {
    
    
                                var d = proInDataColumns.Find(c => string.Equals(c.ColumnName.ToLower().Trim(), pc.Name.ToLower().Trim(), StringComparison.CurrentCultureIgnoreCase));
                                if (d != null)
                                    pc.SetValue(cn, item[pc.Name], null);
    
    
                        }
                        lst.Add(cn);
                    }
                    return lst;
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
        }
    

    Model class

    public class Item
    {
        public string ItemCode { get; set; }
        public string Cost { get; set; }
        public override string ToString()
        {
            return "ItemCode : " + ItemCode + ", Cost : " + Cost;
        }
    }
    

    Create DataTable

    public DataTable getTable()
    {
        DataTable dt = new DataTable();
        dt.Columns.Add(new DataColumn("ItemCode", typeof(string)));
        dt.Columns.Add(new DataColumn("Cost", typeof(string)));
        DataRow dr;
        for (int i = 0; i < 10; i++)
        {
            dr = dt.NewRow();
            dr[0] = "ItemCode" + (i + 1);
            dr[1] = "Cost" + (i + 1);
            dt.Rows.Add(dr);
        }
        return dt;
    }
    

    Now we can convert this DataTable to List like below:

    DataTable dt = getTable();
    List<Item> lst = dt.ToCollection<Item>();
    foreach (Item cn in lst)
    {
        Response.Write(cn.ToString() + "<BR/>");
    }
    

    Hope will help you

    0 讨论(0)
  • 2020-12-01 02:12

    The .ToList() is in the wrong place, and if some fields can be null you'll have to deal with these as they wont convert to Int64 if they're null

    DataTable dt = GetDataFromDB();
    List<Cards> target = dt.AsEnumerable().Select(
      x => new Cards { CardID = (Int64)(x.ItemArray[0] ?? 0) }).ToList();
    
    0 讨论(0)
  • 2020-12-01 02:14

    Here is a simple way to convert to generic list in c# with Where condition

    List<Filter> filter = ds.Tables[0].AsEnumerable()
                            .Where(x => x.Field<int>("FilterID") == 5)
                            .Select(row => new Filter
                            {
                                FilterID = row.Field<int>("FilterID"),
                                FilterName = row.Field<string>("FilterName")
                            }).ToList();
    

    First Define properties and use as per

    public class Filter
    {
        public int FilterID { get; set; }
        public string FilterName { get; set; }
    }
    

    Put Package:

    using System.Linq;
    using System.Collections.Generic;
    
    0 讨论(0)
  • 2020-12-01 02:18

    I think all the solutions can be improved and make the method more general if you use some conventions and reflection. Let's say you name your columns in the datatable the same name as the properties in your object, then you could write something that look at all your properties of your object and then look up that column in the datatable to map the value.

    I did the opposite, that is... from IList to datatable, and the code I wrote can be seen at: http://blog.tomasjansson.com/convert-datatable-to-generic-list-extension/

    It shouldn't be that hard to go the other way, and it should be that hard to overload the functions so you can provide information of which properties you want to include or exclude.

    EDIT: So the code to make it work is:

    public static class DataTableExtensions
    {
        private static Dictionary<Type,IList<PropertyInfo>> typeDictionary = new Dictionary<Type, IList<PropertyInfo>>();
        public static IList<PropertyInfo> GetPropertiesForType<T>()
        {
            var type = typeof(T);
            if(!typeDictionary.ContainsKey(typeof(T)))
            {
                typeDictionary.Add(type, type.GetProperties().ToList());
            }
            return typeDictionary[type];
        }
    
        public static IList<T> ToList<T>(this DataTable table) where T : new()
        {
            IList<PropertyInfo> properties = GetPropertiesForType<T>();
            IList<T> result = new List<T>();
    
            foreach (var row in table.Rows)
            {
                var item = CreateItemFromRow<T>((DataRow)row, properties);
                result.Add(item);
            }
    
            return result;
        }
    
        private static T CreateItemFromRow<T>(DataRow row, IList<PropertyInfo> properties) where T : new()
        {
            T item = new T();
            foreach (var property in properties)
            {
                property.SetValue(item, row[property.Name], null);
            }
            return item;
        }
    
    }
    

    If you have a DataTable you can just write yourTable.ToList<YourType>() and it will create the list for you. If you have more complex type with nested objects you need to update the code. One suggestion is to just overload the ToList method to accept an params string[] excludeProperties which contains all your properties that shouldn't be mapped. Of course you can add some null checking in the foreach loop of the CreateItemForRow method.

    UPDATE: Added static dictionary to store the result from the reflection operation to make it a little bit faster. I haven't compiled the code, but it should work :).

    0 讨论(0)
  • 2020-12-01 02:27

    well its the one line solution

    it depends on whether or not you know the data in the database is all valid and will not contain anything that will break the above

    eg a nullable field whenre you dont expect it - maybe due to a left join int eh sql that genertates the data.

    So if you have validated the data before then yeah - I was goign to suggest some linq - but you got tht down.

    If you need some validation however you should probably just loop through the datarows, generate your object as above and add it to the collection ... this will also allow you to handle errors in one row and still process the rest.

    Thats the way i see it anyway

    (damn i came on to downvote something so my rep was 1024)

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