Tuesday, January 30, 2007

Object to DataTable

When I lay my hands on ASP.NET 2.0, I was thrilled to use Generics in the form of List( of T) and used it to create collections of my business objects. I was even more excited to use the ObjectDataSource control and bind it to a GridView. But when I tried sorting the GridView, I got a runtime error which said that sorting of List (of T) is not supported and suggested using a DataTable or DataSet! Googling for a few minutes, I learned that to enable sorting for my collection class (in this case a Generic List), I need to first create a custom collection and then implement the IComparable interface. And then, I had to setThe ObjectDataSource's SortExpression.

I was too lazy to do all this and also didn't want my code scattered in multiple events so I decided to write a bit of 'reflective' code to convert my List(of T) to a DataTable. All I had to do then is Databind the DataTable and let GridView handle sorting.

The class cList2Table has a method to convert your System.Generics.List(of T) to a DataTable. cList2Table takes a generic list as its constructor parameter and returns a DataTable when you call the GetTable() method.

Imports System.Reflection
Public Class cObjectToTable(Of T)
Dim objectCollection As List(Of T)
Public Sub New(ByVal objectCollection As List(Of T))
Me.objectCollection = objectCollection
End Sub
Public Function GetTable() As DataTable
Dim table As New DataTable
Dim objectType As Type = GetType(T)
Dim objectProperties As PropertyInfo() = objectType.GetProperties
'create a column for each property in the class
For Each propertyItem As PropertyInfo In objectProperties table.Columns.Add(New DataColumn(propertyItem.Name, propertyItem.PropertyType))
For Each item As T In objectCollection
'create a new row based on the table structure we just created Dim row As DataRow = table.NewRow()
'copy object data to the datarow
For Each propertyItem As PropertyInfo In objectProperties
row(propertyItem.Name) = propertyItem.GetValue(item, Nothing)
'add row to the table
Return table
End Function
End Class

Now I usually like to see schema in the GridView during design time,So I filled my typed DataSet with the following snippet of code.

Dim loTable As New dsSection.dtSectionDataTable


Mark said...

Can you post some code on how you would call this useing an object data source? I don't get the (of t) stuff yet.



Kinosabi said...

Pass the object reference in the (Of T) portion

Of T Class

Public class MyObject(Of T)

public Sub New(byval Objlist as List(of T))

End Class

Public Class MyObject

Private objList as List(Of SomeObject)
Private objMyObject(Of MyObject)(objList)

End Class

BJS said...

Nice bit of code. Was going to try to figure it out myself, but you saved me some work. Thanks.

Richard said...

Please help:
I have to send the collection of objects as a parameter or the definition of the object of the collection.

I get an error indicating that

"Argument not specified for parameter 'objectCollection' of 'Public Sub New(objectCollection As System.Collections.Generic.List(Of T))'."

can help, my code is:

Dim DT as DataTable
Dim conv As New ConvertColection(Of MyCollection)

DT = conv.GetTable()

Edwin said...

'First I converted my array of to a List of objects, then I referenced my data in the second set of parenthesis when I called the generic class.

Dim ListofmyObjects As New List(Of myObjectType)(myOldArrayofObjects)

Dim objList As New cObjectToTable(Of myObjectType)(ListofmyObjects)

FW said...

this is absolutely terrific, you saved me quite some time :)

great work!

Ramiro Fernando said...

Hi, I think that implement a sorteable List isn't difficult. Maybe you should see http://www.codeproject.com/KB/linq/bindinglist_sortable.aspx.

There's not reason to use a datatable o dataset if you use a domain objects model.


Ramiro Fernando said...

I add: http://msdn.microsoft.com/en-us/library/aa480736.aspx

this is a great reference

ComputerCowboy said...

Why does VB even exist?

public class ListToDataTable

private List _list;

public ListToDataTable(List list)
this._list = list;

public DataTable ToDataTable()
var dt = new DataTable();
var type = typeof(T);
var properties = type.GetProperties();
foreach (var property in properties)
var dc = new DataColumn(property.Name);
foreach (T item in this._list)
var dr = dt.NewRow();
foreach (var property in properties)
dr[property.Name] = property.GetValue(item, null);

return dt;