Click here to Skip to main content
Click here to Skip to main content


, 4 Nov 2006 CPOL
Rate this:
Please Sign up or sign in to vote.
How to flatten collections for an ObjectDataSource using the Adapter Pattern.


This is a class and example of how to flatten a domain model into a DataTable to ease the use of an ObjectDataSource.


I have been using OR/M modeling for a while now in WinForms applications. Recently, I had the need for an ASP.NET application, and quickly got very frustrated with the ObjectDataSource. I don't want to get into a debate between DataSets and Collections. Suffice it to say, I use strongly typed collections.


When using a non-flat (hierarchical) domain model, it is impossible to bind to a complex property. For instance, in the Domain Model below, I will need to show the Instructor's FullName in the class list and subsequently be able to edit it. However, while I can bind to the Instructor, it will show whatever is in the Person's toString() method. This is fine for display, but what about editing? I could implement IConvertible<T>, but I don't need this functionality outside of my presentation layer. Therefore, let's use the Adaptor design pattern to adapt a collection of objects (or just a single object) into a DataTable.

This approach also yields a number of other advantages. The ObjectDataSource doesn't sort or page well without a lot of plumbing. When bound to a DataTable, it handles this natively so no extra code needs to be written.


Using the code

Since Course doesn't have the display properties "InstructorId", "InstructorFullName", or "AvailableSlots", we can essentially mix them in to the data type as if they were a part of the class. Dynamic languages like Ruby and Python allow this on the object level, negating the need to do this in the conversion. C#3 (and VB9) have something called extension methods, but so far no mention has been made of extension properties (which we need for data binding).

public static DataTable FindAll()
    DataTableAdapter<Course> dta = new DataTableAdapter<Course>();
    dta.AddColumn("InstructorId", typeof(string), 
        delegate(Course c) { return c.Instructor.Id; });
    dta.AddColumn("InstructorFullName", typeof(string), 
        delegate(Course c) { return c.Instructor.FullName; });
    dta.AddColumn("AvailableSlots", typeof(string), 
        delegate(Course c) { return c.MaxStudents - c.Students.Count; });
    return dta.GetDataTable(CourseService.FindAll());

Potential Issues

Obviously, reflection is being used extensively here. This may cause some performance issues depending on how large an object base is being used.


The full source for the DataTableAdapter is in the App_Code folder under DataTableAdapter.cs. It is well commented and fairly self-explanatory. I would like to point out the part for which I had to search. It has to do with detecting a nullable type and then getting its underlying type. The reason this is necessary is because a DataTable will not accept a nullable type in a column definition. It uses DBNull for this value. Anyways, here is an excerpt...

//Get all the pi's once.
PropertyInfo[] pi = typeof(T).GetProperties();

Type piType;
//Add all the properties as columns
for (int i = 0; i < pi.Length; i++)
    piType = pi[i].PropertyType;

    //Data tables don't accept nullables in the column type.  Therefore,
    //when we encounter a nullable, we need to get it's underlying type.
    if (piType.IsGenericType && 
           piType.GetGenericTypeDefinition() == typeof(Nullable<>))
        piType = Nullable.GetUnderlyingType(piType);

    dt.Columns.Add(new DataColumn(pi[i].Name, piType));


The idea for this came from a Google search that yielded this result at Brendan Tompkin's blog.


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

Craig G. Wilson
Web Developer
United States United States
I work at a financial services firm using mostly .NET. I enjoy my job immensely and love teaching, training, and mentoring younger developers.

Comments and Discussions

NewsSource code available online PinmemberGilad Khen30-May-09 17:38 
Questiondreamviewer question PinmemberSSN4-Jun-08 6:14 
GeneralJust what I've been looking for Pinmemberwaltersm23-Oct-07 23:53 
GeneralRe: Just what I've been looking for PinmemberJafin26-Dec-07 15:05 
GeneralGood Job PinmemberMarco225020-Sep-07 19:20 
GeneralCollections PinmemberLurkingVariable21-Jan-07 11:43 
GeneralRe: Collections PinmemberCraig G. Wilson21-Jan-07 16:50 
Hi LV,
Thanks for your remarks. I actually have translated this to VB for some coworkers, so I'll post it up here as a seperate download.
As for your other question, I believe the answer is simple. When I use the DataTableAdapter, I don't use it directly. I create a wrapper class for the object I'm attempting to display. This wrapper class can be static (VB: Shared) because it doesn't really do anything but redirect calls to the appropriate domain/infrastructure layers. Hence, this becomes a presentation layer class. For example:
The example above of consisting of the Findall Method would be apart of a larger class. This large adapter class would be the only class with which the ObjectDataSource interacts so that maintenance only occurs in one place, thus seperating more "business like methods" away from the presentation layer.
Public Class CourseAdapter
	Public Shared Function FindAll() As DataTable
		Dim dta As New DataTableAdapter(Of Course)
		'add columns here as necessary
		Return dta.GetDataTable(CourseService.FindAll())
	End Function
	Public Shared Function Insert(ByVal description As String, _
					ByVal maxStudents As Integer, _
					ByVal name As String) 'or more as necessary
		'Insert the record
	End Function
	Public Shared Function Update(...)
		'Update a record	
	End Function
	Public Function Delete(...)
		'Delete a record		
	End Function
End Class
Hope this is what you were looking for. The tricky part is figuring out which parameters to place into each method. The ObjectDataSource is fairly strict and doesn't always tell you what you need.


GeneralRe: Collections PinmemberLurkingVariable21-Jan-07 16:59 
GeneralData Base Connectivity PinmemberFazal_qureshi17-Dec-06 23:39 
GeneralRe: Data Base Connectivity PinmemberCraig G. Wilson18-Dec-06 3:45 
QuestionI receive the error: Parameter count mismatch Pinmemberklhkdsjhfksjhdfkjshf15-Nov-06 12:53 
AnswerRe: I receive the error: Parameter count mismatch PinmemberCraig G. Wilson15-Nov-06 13:01 
GeneralRe: I receive the error: Parameter count mismatch PinmemberWilhelm Berg7-Feb-07 11:07 
QuestionSource PinmemberLoneRanger7-Nov-06 9:32 
AnswerRe: Source PinmemberCraig G. Wilson7-Nov-06 9:35 
AnswerRe: Source PinmemberLoneRanger8-Nov-06 7:38 
GeneralRe: Source PinmemberCraig G. Wilson8-Nov-06 7:56 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.150327.1 | Last Updated 4 Nov 2006
Article Copyright 2006 by Craig G. Wilson
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid