tags:

views:

8234

answers:

8

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?

+7  A: 

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.

Christian Hayter
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
Sorting 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
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
It 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
+2  A: 

You may want to check out

http://www.codeproject.com/KB/vb/List2DataSet.aspx

Gives a few different approaches.

apocalypse9
A: 

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.

JDunkerley
+2  A: 

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?

joshua.ewer
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 :-)
Ben
+2  A: 

I've written a small library myself to accomplish this task. It uses reflection only for the first time an object type is to be translated to a datatable. It emits a method that will do all the work translating an object type.

Its the fastest solution i know (thats why i developed it :-) ). You can find it here: ModelShredder on GoogleCode

Currently it is only supporting translation to a DataTable. As you phrased your question, this should be sufficient. Support for DataSets (think of a simple reverse ORM) is already developed, it will be released in two weaks when i am back from vacation :-)

Johannes Rudolph
+2  A: 

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;
}
Lee
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 :-)
Ben
Ok, I had to make two changes, one for the Nullable types and another for null values...t.Columns.Add(propInfo.Name, propInfo.PropertyType);becomesType ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType;t.Columns.Add(propInfo.Name, ColType);androw[propInfo.Name] = propInfo.GetValue(item, null);becomesrow[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value;Thanks for the code :-)
Ben
+2  A: 

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;

}

dfeehely
+1  A: 

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;
    }
Ben