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

DataTableAdapter

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

Introduction

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

Background

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.

Problem

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.

DataStore.png

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).

[DataObjectMethod(DataObjectMethodType.Select)]
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.

Source

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

References

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

License

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 16:38 
Questiondreamviewer question PinmemberSSN4-Jun-08 5:14 
GeneralJust what I've been looking for Pinmemberwaltersm23-Oct-07 22:53 
GeneralRe: Just what I've been looking for PinmemberJafin26-Dec-07 14:05 
GeneralGood Job PinmemberMarco225020-Sep-07 18:20 
GeneralCollections PinmemberLurkingVariable21-Jan-07 10:43 
GeneralRe: Collections PinmemberCraig G. Wilson21-Jan-07 15:50 
GeneralRe: Collections PinmemberLurkingVariable21-Jan-07 15:59 
GeneralData Base Connectivity PinmemberFazal_qureshi17-Dec-06 22:39 
GeneralRe: Data Base Connectivity PinmemberCraig G. Wilson18-Dec-06 2:45 
QuestionI receive the error: Parameter count mismatch Pinmemberklhkdsjhfksjhdfkjshf15-Nov-06 11:53 
AnswerRe: I receive the error: Parameter count mismatch PinmemberCraig G. Wilson15-Nov-06 12:01 
GeneralRe: I receive the error: Parameter count mismatch PinmemberWilhelm Berg7-Feb-07 10:07 
QuestionSource PinmemberLoneRanger7-Nov-06 8:32 
AnswerRe: Source PinmemberCraig G. Wilson7-Nov-06 8:35 
AnswerRe: Source PinmemberLoneRanger8-Nov-06 6:38 

thanks!
 
But what I meant was, that yesterday the .zip seemed to be missing since I got a 404 when I tried downloading.
Now everything works as expected.
 
LR1K
 

GeneralRe: Source PinmemberCraig G. Wilson8-Nov-06 6: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 | Mobile
Web04 | 2.8.140721.1 | Last Updated 4 Nov 2006
Article Copyright 2006 by Craig G. Wilson
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid