Converting Generic Lists or Collections to a DataSet

Today I had a situation where I was calling a web service that returned an array of items.  Here is a sample of the XML the web service was returning. 

<?

xml version="1.0" encoding="utf-8"?>
<
ItemCollection>
   <
item>
      <
FirstName>Keith</FirstName>
      <
LastName>Elder</LastName>
      
<FavoriteColor>Blue</FavoriteColor>
   </
item>
   <
item>
      <
FirstName>Chris</FirstName>
      <
LastName>Risner</LastName>
      
<FavoriteColor>Pink</FavoriteColor>
   </
item>
   <
item>
      <
FirstName>David</FirstName>
      <
LastName>Little</LastName>
      <
FavoriteColor>Carnation Pink</FavoriteColor>
   </
item>
</
ItemCollection>

The web service returned the data as expected but I needed to bind this to a DataGridView in the user interface.  For anyone that has used VS2005 you know this is pretty simple.  I added a new data source of type "Object" and selected my ItemCollection object that was generated from the WSDL of the web service.   I dropped the ItemCollection onto the designer and I had a DataGridView with all of my columns.  So far, I've spent about 30 seconds on this and I've connected to a web service and bound data to the UI.  I was going to be done with this in a few minutes.  I proceeded to take out the columns that I didn't want showing and built the solution and everything looked great. 

I then referred back to the spec and noticed something that I missed.  The columns need to be sortable in the UI.  This poses a problem because the data that is coming back from the web service gets converted into an array of items (items[]).  Although we can bind an array to a DataGridView there isn't an easy way to make the DataGridView sort this information based on each column.

I stared at my screen for a few minutes and came to the conclusion that I was going to need to convert the items[] to a DataSet since when bound to a DataGridView it would provide automatic sorting as well as filtering down the road in case someone decided they wanted to search this data (which they typically do). I started then writing a CollectionToDataSet object that would take a collection of items and convert the collection to a DataSet.  When you decide to go down this path to make this type of library you really hate building something that only works for one type of object.  I first got the new class working but it only worked with the type of object I was working with.  During my playing around with the new class a light bulb went off and it hit me this would be a good place to implement a Generic. 

Here is the end result of the class which uses a Generic to figure out which type of object is being passed in.  The only thing it must do is implement the ICollection interface and things work.  Here is what I came up with.

    /// <summary>

    /// This will take anything that implements the ICollection interface and convert

    /// it to a DataSet.

    /// </summary>

    /// <example>

    /// CollectiontoDataSet converter = new CollectionToDataSet<Letters[]>(letters);

    /// DataSet ds = converter.CreateDataSet();

    /// </example>

    /// <typeparam name="T"></typeparam>

    public class CollectionToDataSet<T> where T : System.Collections.ICollection

    {

        T _collection;

        public CollectionToDataSet(T list)

        {

            _collection = list;

        }

 

        private PropertyInfo[] _propertyCollection = null;

        private PropertyInfo[] PropertyCollection

        {

            get

            {

                if (_propertyCollection == null)

                {

                    _propertyCollection = GetPropertyCollection();

                }

                return _propertyCollection;

            }

        }

 

        private PropertyInfo[] GetPropertyCollection()

        {

            if (_collection.Count > 0)

            {

                IEnumerator enumerator = _collection.GetEnumerator();

                enumerator.MoveNext();

                return enumerator.Current.GetType().GetProperties();

            }

            return null;

        }

 

        public DataSet CreateDataSet()

        {

            DataSet ds = new DataSet("GridDataSet");

            ds.Tables.Add(FillDataTable());

            return ds;

        }

 

        private DataTable FillDataTable()

        {

            IEnumerator enumerator = _collection.GetEnumerator();

            DataTable dt = CreateDataTable();

            while (enumerator.MoveNext())

            {

                dt.Rows.Add(FillDataRow(dt.NewRow(),enumerator.Current));

            }

            return dt;

        }

 

        private DataRow FillDataRow(DataRow dataRow, object p)

        {

            foreach (PropertyInfo property in PropertyCollection)

            {

                dataRow[property.Name.ToString()] = property.GetValue(p, null);

            }

            return dataRow;

        }

 

        private DataTable CreateDataTable()

        {

            DataTable dt = new DataTable("GridDataTable");

            foreach (PropertyInfo property in PropertyCollection)

            {

                dt.Columns.Add(property.Name.ToString());

            }

            return dt;

        }

    }

 

There you go!  A class to take any type of object that implements the ICollection interface and convert it to a DataSet.

 

As I was writing this article I thought of another way this could be done.  Since the items[] is serializable to XML and a DataSet can take XML and convert that to a DataSet through the ReadXml() method, what I could have done is convert the object to XML, then have a DataSet just read in the XML.  Just food for thought.  I may play with that later on to see which one is "faster".  I can tell you that serializing the object and then converting it would be a lot less code to write initially, however, this class will probably come in handy more than not.

 

Let me know what you think about the class or if you have any ideas on how to improve it or ways you would have done it differently.  I've attached the class file to this post for those that want to download it and give it whirl.

posted @ Friday, March 10, 2006 9:07 PM

Print

Comments on this entry:

 re: Converting Generic Lists or Collections to a DataSet

Left by Lemuel at 8/6/2007 1:07 PM
Gravatar

How do you create an instance of the class?

# re: Converting Generic Lists or Collections to a DataSet

Left by Keith Elder at 8/6/2007 1:17 PM
Gravatar

I'm not understanding the question, which class are you referring to?

 re: Converting Generic Lists or Collections to a DataSet

Left by Jeff Brumley at 4/14/2008 3:29 PM
Gravatar

I converted this code over to VB.net - hope this helps somebody! Please excuse the formatting...

Imports System.Data
Imports System.Reflection

Public Class CollectionToDataSet

Private _collection As ICollection
Private _propertyCollection() As PropertyInfo = Nothing

Private ReadOnly Property PropertyCollection() As PropertyInfo()
Get
If _propertyCollection Is Nothing Then
_propertyCollection = GetPropertyCollection()
End If
Return _propertyCollection
End Get
End Property

Private Function GetPropertyCollection() As PropertyInfo()

If (_collection.Count > 0) Then
Dim enumerator As IEnumerator = _collection.GetEnumerator()
enumerator.MoveNext()
Return enumerator.Current.GetType().GetProperties()
Else
Return Nothing
End If
End Function

Public Function CreateDataSet() As DataSet
Dim ds As DataSet = New DataSet("GridDataSet")
ds.Tables.Add(FillDataTable())
Return ds
End Function

Private Function FillDataTable() As DataTable
Dim enumerator As IEnumerator = _collection.GetEnumerator()
Dim dt As DataTable = CreateDataTable()
While enumerator.MoveNext()
dt.Rows.Add(FillDataRow(dt.NewRow(), enumerator.Current))
End While
Return dt
End Function

Private Function FillDataRow(ByRef dataRow As DataRow, ByRef p As Object) As DataRow
For Each pi As PropertyInfo In PropertyCollection
dataRow(pi.Name.ToString()) = pi.GetValue(p, Nothing)
Next
Return dataRow
End Function

Private Function CreateDataTable() As DataTable
Dim dt As DataTable = New DataTable("GridDataTable")
For Each pi As PropertyInfo In PropertyCollection
dt.Columns.Add(pi.Name.ToString())
Next
Return dt
End Function

Public Sub New(ByRef coll As ICollection)
_collection = coll
End Sub


End Class

# re: Converting Generic Lists or Collections to a DataSet

Left by Mike Hestness at 4/26/2008 1:06 PM
Gravatar

Hi Keith, Great article on converting collections to a dataset. I can't seem to find the class file in this post anywhere and when I try to compile the code snippet I get the error "Error1-Using the generic type 'System.Collections.Generic.IEnumerator<T>' requires '1' type arguments". Can you send me the class file or point me in the right direction? Thanks a million!

# re: Converting Generic Lists or Collections to a DataSet

Left by Ian at 5/8/2008 2:54 AM
Gravatar

Hi Keith.

I've used your code to create an extension method for an IEnumerable object, so you can just call .ToDataSet on a collection.

I've posted this entry with the code: http://iandykes.blogspot.com/2008/05/ienumerable-to-dataset-extension-method.html

Ian

# re: Converting Generic Lists or Collections to a DataSet

Left by Keith Elder at 5/8/2008 8:11 AM
Gravatar

Very cool Mike. A great implementation for today's new features of the platform.

 re: Converting Generic Lists or Collections to a DataSet

Left by Plesva, Mexilus at 7/1/2008 2:26 PM

The answer to "Error1-Using the generic type 'System.Collections.Generic.IEnumerator<T>' requires '1' type arguments" is to include the following statement:

using System.Collections;

 re: Converting Generic Lists or Collections to a DataSet

Left by Gerard at 7/12/2008 8:07 AM
Gravatar

Like Mike's comment at the top, I don't really get how to implement this..

I have a generic list of houses declared by

List<house> houses;

how do I convert this into a DataSet ?

 re: Converting Generic Lists or Collections to a DataSet

Left by Bob at 7/21/2008 3:16 PM

@Gerard

Look at the comments in the code above.... he gives you an example

# re: Converting Generic Lists or Collections to a DataSet

Left by parke at 8/29/2008 10:14 AM
Gravatar

Thank you

# re: Converting Generic Lists or Collections to a DataSet

Left by rüya tabiri at 8/29/2008 10:15 AM
Gravatar

thank youuu

Your comment:






 
 
 
Please add 1 and 6 and type the answer here:
 

Live Comment Preview:

 
«August»
SunMonTueWedThuFriSat
272829303112
3456789
10111213141516
17181920212223
24252627282930
31123456