I have a Generic list of Objects. Each object has 9 string properties. I want to turn that list into a dataset that i can pass to a datagridview......Whats the best way to go about doing this?
-
1possible duplicate of [How do I transform a List
into a DataSet?](http://stackoverflow.com/questions/523153/how-do-i-transform-a-listt-into-a-dataset) – Mar 12 '14 at 12:46
8 Answers
I apologize for putting an answer up to this question, but I figured it would be the easiest way to view my final code. It includes fixes for nullable types and null values :-)
public static DataSet ToDataSet<T>(this IList<T> list)
{
Type elementType = typeof(T);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
t.Columns.Add(propInfo.Name, ColType);
}
//go through each property on T and add each value to the table
foreach (T item in list)
{
DataRow row = t.NewRow();
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
t.Rows.Add(row);
}
return ds;
}

- 2,875
- 4
- 41
- 39
-
3Thanks for this, great snippet :) Just one bugfix, i added if (list.Count() != 0) before foreach, because, if list you wan't to convert is empty, code will throw an exception. – onedevteam.com Oct 01 '14 at 17:59
-
1One note about this snippet - you need to add `t.AcceptChanges()` before `return ds;`, otherwise, the table will be interpreted as having all those rows that you added as pending changes. This rarely causes any problems, but it can. – Andrew Gray Jun 13 '16 at 15:16
-
@AndrewGray I guess this means the rows are coming over with a 'dirty' flag because they were added? That might be a desired behavior? – Bennett Dill Jun 14 '16 at 01:38
-
It can be, but not always. Most of the time - I'd say > 90% - it's harmless. – Andrew Gray Jun 14 '16 at 13:27
Have you tried binding the list to the datagridview directly? If not, try that first because it will save you lots of pain. If you have tried it already, please tell us what went wrong so we can better advise you. Data binding gives you different behaviour depending on what interfaces your data object implements. For example, if your data object only implements IEnumerable
(e.g. List
), you will get very basic one-way binding, but if it implements IBindingList
as well (e.g. BindingList
, DataView
), then you get two-way binding.

- 30,581
- 6
- 72
- 99
-
binding directly wont work out very often: It is slow, and sorting is a pain. If its just up to 1000rows its fine, for everything else i recommend a fast dataTable translator like my ModelShredder (see below) – Johannes Rudolph Aug 07 '09 at 16:26
-
1Sorting is a pain. So is filtering. So is editing. It's possible to build an object that supports all of the use cases that the DataTable does, but it's not a trivial amount of work - especially compared with just copying the data to a DataTable. – Robert Rossney Aug 07 '09 at 20:23
-
yup, thats why i've written modelshredder. Im afraid that editing is of course not supported, but i dont see this as an issues because i think editing data in a table should be avoided for the above mentioned reasons. There is always excel :-) – Johannes Rudolph Aug 08 '09 at 09:19
-
1It depends on your use case. If you are writing a 2-tier app, then sorting, filtering, paging etc are most easily done in a DataSet/Table/View. However, if you are writing a 3-tier app, then all those things have been done already on the business tier, and all you have to do on the presentation tier is a very dumb one-way binding to a generic List. – Christian Hayter Aug 09 '09 at 09:17
There is a bug with Lee's extension code above, you need to add the newly filled row to the table t when iterating throught the items in the list.
public static DataSet ToDataSet<T>(this IList<T> list) {
Type elementType = typeof(T);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
//add a column to table for each public property on T
foreach(var propInfo in elementType.GetProperties())
{
t.Columns.Add(propInfo.Name, propInfo.PropertyType);
}
//go through each property on T and add each value to the table
foreach(T item in list)
{
DataRow row = t.NewRow();
foreach(var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null);
}
//This line was missing:
t.Rows.Add(row);
}
return ds;
}
You could create an extension method to add all property values through reflection:
public static DataSet ToDataSet<T>(this IList<T> list)
{
Type elementType = typeof(T);
DataSet ds = new DataSet();
DataTable t = new DataTable();
ds.Tables.Add(t);
//add a column to table for each public property on T
foreach(var propInfo in elementType.GetProperties())
{
t.Columns.Add(propInfo.Name, propInfo.PropertyType);
}
//go through each property on T and add each value to the table
foreach(T item in list)
{
DataRow row = t.NewRow();
foreach(var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null);
}
}
return ds;
}

- 142,018
- 20
- 234
- 287
-
Thanks for the code, one small problem though, Nullable types are bombing... I'm going to try to modify it to accommodate them, but I'm not a reflection pro. If I get something worked out, I'll post an update :-) – Bennett Dill Sep 15 '10 at 03:28
-
1Ok, I had to make two changes, one for the Nullable types and another for null values... t.Columns.Add(propInfo.Name, propInfo.PropertyType); becomes Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; t.Columns.Add(propInfo.Name, ColType); and row[propInfo.Name] = propInfo.GetValue(item, null); becomes row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value; Thanks for the code :-) – Bennett Dill Sep 15 '10 at 15:32
Brute force code to answer your question:
DataTable dt = new DataTable();
//for each of your properties
dt.Columns.Add("PropertyOne", typeof(string));
foreach(Entity entity in entities)
{
DataRow row = dt.NewRow();
//foreach of your properties
row["PropertyOne"] = entity.PropertyOne;
dt.Rows.Add(row);
}
DataSet ds = new DataSet();
ds.Tables.Add(dt);
return ds;
Now for the actual question. Why would you want to do this? As mentioned earlier, you can bind directly to an object list. Maybe a reporting tool that only takes datasets?

- 3,944
- 3
- 25
- 35
-
An answer to why one wants to do this, me anyway, is WCF. Services really don't like putting generics on the wire. I'm writing some code for returning paged and ordered results from a repository and I'm coping out with a DataSet for now... One reason being that the fields being returned aren't always the same... I'm not sure if that will fly though, it might need DTO, which means I have other issues, but I digress :-) – Bennett Dill Sep 15 '10 at 03:33
I have slightly modified the accepted answer by handling value types. I came across this when trying to do the following and because GetProperties() is zero length for value types I was getting an empty dataset. I know this is not the use case for the OP but thought I'd post this change in case anyone else came across the same thing.
Enumerable.Range(1, 10).ToList().ToDataSet();
public static DataSet ToDataSet<T>(this IList<T> list)
{
var elementType = typeof(T);
var ds = new DataSet();
var t = new DataTable();
ds.Tables.Add(t);
if (elementType.IsValueType)
{
var colType = Nullable.GetUnderlyingType(elementType) ?? elementType;
t.Columns.Add(elementType.Name, colType);
} else
{
//add a column to table for each public property on T
foreach (var propInfo in elementType.GetProperties())
{
var colType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;
t.Columns.Add(propInfo.Name, colType);
}
}
//go through each property on T and add each value to the table
foreach (var item in list)
{
var row = t.NewRow();
if (elementType.IsValueType)
{
row[elementType.Name] = item;
}
else
{
foreach (var propInfo in elementType.GetProperties())
{
row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;
}
}
t.Rows.Add(row);
}
return ds;
}

- 1,379
- 1
- 17
- 30
I found this code on Microsoft forum. This is so far one of easiest way, easy to understand and use. This has saved me hours , I have customized it as extension method without any change to actual method. Below is the code. it doesn't require much explanation.
You can use two function signature with same implementation
1) public static DataSet ToDataSetFromObject(this object dsCollection)
2) public static DataSet ToDataSetFromArrayOfObject( this object[] arrCollection) . I 'll be using this one for example.
// <summary>
// Serialize Object to XML and then read it into a DataSet:
// </summary>
// <param name="arrCollection">Array of object</param>
// <returns>dataset</returns>
public static DataSet ToDataSetFromArrayOfObject( this object[] arrCollection)
{
DataSet ds = new DataSet();
try {
XmlSerializer serializer = new XmlSerializer(arrCollection.GetType);
System.IO.StringWriter sw = new System.IO.StringWriter();
serializer.Serialize(sw, dsCollection);
System.IO.StringReader reader = new System.IO.StringReader(sw.ToString());
ds.ReadXml(reader);
} catch (Exception ex) {
throw (new Exception("Error While Converting Array of Object to Dataset."));
}
return ds;
}
To use this extension in code
Country[] objArrayCountry = null;
objArrayCountry = ....;// populate your array
if ((objArrayCountry != null)) {
dataset = objArrayCountry.ToDataSetFromArrayOfObject();
}

- 2,232
- 2
- 20
- 25
One option would be to use a System.ComponenetModel.BindingList rather than a list.
This allows you to use it directly within a DataGridView. And unlike a normal System.Collections.Generic.List updates the DataGridView on changes.

- 12,355
- 5
- 41
- 45