Convert generic List/Enumerable to DataTable?

后端 未结 27 2146
臣服心动
臣服心动 2020-11-21 23:20

I have few methods that returns different Generic Lists.

Exists in .net any class static method or whatever to convert any list into a datatable? The only thing tha

相关标签:
27条回答
  • 2020-11-21 23:57

    If you want to use reflection and set columns order/ include only some columns/ Exclude some columns try this:

            private static DataTable ConvertToDataTable<T>(IList<T> data, string[] fieldsToInclude = null,
    string[] fieldsToExclude = null)
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
            DataTable table = new DataTable();
            foreach (PropertyDescriptor prop in properties)
            {
                if ((fieldsToInclude != null && !fieldsToInclude.Contains(prop.Name)) ||
                    (fieldsToExclude != null && fieldsToExclude.Contains(prop.Name)))
                    continue;
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }
    
            foreach (T item in data)
            {
                var atLeastOnePropertyExists = false;
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                {
    
                    if ((fieldsToInclude != null && !fieldsToInclude.Contains(prop.Name)) ||
    (fieldsToExclude != null && fieldsToExclude.Contains(prop.Name)))
                        continue;
    
                    row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                    atLeastOnePropertyExists = true;
                }
    
                if(atLeastOnePropertyExists) table.Rows.Add(row);
            }
    
    
            if (fieldsToInclude != null)
                SetColumnsOrder(table, fieldsToInclude);
    
            return table;
    
        }
    
        private static void SetColumnsOrder(DataTable table, params String[] columnNames)
        {
            int columnIndex = 0;
            foreach (var columnName in columnNames)
            {
                table.Columns[columnName].SetOrdinal(columnIndex);
                columnIndex++;
            }
        }
    
    0 讨论(0)
  • 2020-11-21 23:58

    I had to modify Marc Gravell's sample code to handle nullable types and null values. I have included a working version below. Thanks Marc.

    public static DataTable ToDataTable<T>(this IList<T> data)
    {
        PropertyDescriptorCollection properties = 
            TypeDescriptor.GetProperties(typeof(T));
        DataTable table = new DataTable();
        foreach (PropertyDescriptor prop in properties)
            table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
        foreach (T item in data)
        {
            DataRow row = table.NewRow();
            foreach (PropertyDescriptor prop in properties)
                 row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
            table.Rows.Add(row);
        }
        return table;
    }
    
    0 讨论(0)
  • 2020-11-21 23:59

    I realize that this has been closed for a while; however, I had a solution to this specific problem but needed a slight twist: the columns and data table needed to be predefined / already instantiated. Then I needed to simply insert the types into the data table.

    So here's an example of what I did:

    public static class Test
    {
        public static void Main()
        {
            var dataTable = new System.Data.DataTable(Guid.NewGuid().ToString());
    
            var columnCode = new DataColumn("Code");
            var columnLength = new DataColumn("Length");
            var columnProduct = new DataColumn("Product");
    
            dataTable.Columns.AddRange(new DataColumn[]
                {
                    columnCode,
                    columnLength,
                    columnProduct
                });
    
            var item = new List<SomeClass>();
    
            item.Select(data => new
            {
                data.Id,
                data.Name,
                data.SomeValue
            }).AddToDataTable(dataTable);
        }
    }
    
    static class Extensions
    {
        public static void AddToDataTable<T>(this IEnumerable<T> enumerable, System.Data.DataTable table)
        {
            if (enumerable.FirstOrDefault() == null)
            {
                table.Rows.Add(new[] {string.Empty});
                return;
            }
    
            var properties = enumerable.FirstOrDefault().GetType().GetProperties();
    
            foreach (var item in enumerable)
            {
                var row = table.NewRow();
                foreach (var property in properties)
                {
                    row[property.Name] = item.GetType().InvokeMember(property.Name, BindingFlags.GetProperty, null, item, null);
                }
                table.Rows.Add(row);
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-22 00:00
    It's also possible through XmlSerialization.
    The idea is - serialize to `XML` and then `readXml` method of `DataSet`.
    
    I use this code (from an answer in SO, forgot where)
    
            public static string SerializeXml<T>(T value) where T : class
        {
            if (value == null)
            {
                return null;
            }
    
            XmlSerializer serializer = new XmlSerializer(typeof(T));
    
            XmlWriterSettings settings = new XmlWriterSettings();
    
            settings.Encoding = new UnicodeEncoding(false, false);
            settings.Indent = false;
            settings.OmitXmlDeclaration = false;
            // no BOM in a .NET string
    
            using (StringWriter textWriter = new StringWriter())
            {
                using (XmlWriter xmlWriter = XmlWriter.Create(textWriter, settings))
                {
                   serializer.Serialize(xmlWriter, value);
                }
                return textWriter.ToString();
            }
        }
    
    so then it's as simple as:
    
                string xmlString = Utility.SerializeXml(trans.InnerList);
    
            DataSet ds = new DataSet("New_DataSet");
            using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
            { 
                ds.Locale = System.Threading.Thread.CurrentThread.CurrentCulture;
                ds.ReadXml(reader); 
            }
    
    Not sure how it stands against all the other answers to this post, but it's also a possibility.
    
    0 讨论(0)
  • 2020-11-22 00:01

    A small change to Marc's answer to make it work with value types like List<string> to data table:

    public static DataTable ListToDataTable<T>(IList<T> data)
    {
        DataTable table = new DataTable();
    
        //special handling for value types and string
        if (typeof(T).IsValueType || typeof(T).Equals(typeof(string)))
        {
    
            DataColumn dc = new DataColumn("Value", typeof(T));
            table.Columns.Add(dc);
            foreach (T item in data)
            {
                DataRow dr = table.NewRow();
                dr[0] = item;
                table.Rows.Add(dr);
            }
        }
        else
        {
            PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(typeof(T));
            foreach (PropertyDescriptor prop in properties)
            {
                table.Columns.Add(prop.Name, Nullable.GetUnderlyingType(prop.PropertyType) ?? prop.PropertyType);
            }
            foreach (T item in data)
            {
                DataRow row = table.NewRow();
                foreach (PropertyDescriptor prop in properties)
                {
                    try
                    {
                        row[prop.Name] = prop.GetValue(item) ?? DBNull.Value;
                    }
                    catch (Exception ex)
                    {
                        row[prop.Name] = DBNull.Value;
                    }
                }
                table.Rows.Add(row);
            }
        }
        return table;
    }
    
    0 讨论(0)
  • 2020-11-22 00:02

    This link on MSDN is worth a visit: How to: Implement CopyToDataTable<T> Where the Generic Type T Is Not a DataRow

    This adds an extension method that lets you do this:

    // Create a sequence. 
    Item[] items = new Item[] 
    { new Book{Id = 1, Price = 13.50, Genre = "Comedy", Author = "Gustavo Achong"}, 
      new Book{Id = 2, Price = 8.50, Genre = "Drama", Author = "Jessie Zeng"},
      new Movie{Id = 1, Price = 22.99, Genre = "Comedy", Director = "Marissa Barnes"},
      new Movie{Id = 1, Price = 13.40, Genre = "Action", Director = "Emmanuel Fernandez"}};
    
    // Query for items with price greater than 9.99.
    var query = from i in items
                 where i.Price > 9.99
                 orderby i.Price
                 select i;
    
    // Load the query results into new DataTable.
    DataTable table = query.CopyToDataTable();
    
    0 讨论(0)
提交回复
热议问题