Click here to Skip to main content
15,861,168 members
Articles / Web Development / ASP.NET
Article

DataTableAdapter

Rate me:
Please Sign up or sign in to vote.
5.00/5 (11 votes)
4 Nov 2006CPOL2 min read 69.6K   376   38   17
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).

C#
[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...

C#
//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)


Written By
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

 
Questiondreamviewer question Pin
SSN4-Jun-08 5:14
SSN4-Jun-08 5:14 
GeneralJust what I've been looking for Pin
waltersm23-Oct-07 22:53
waltersm23-Oct-07 22:53 
GeneralRe: Just what I've been looking for Pin
Jafin26-Dec-07 14:05
Jafin26-Dec-07 14:05 
GeneralGood Job Pin
Marco225020-Sep-07 18:20
Marco225020-Sep-07 18:20 
GeneralCollections Pin
LurkingVariable21-Jan-07 10:43
LurkingVariable21-Jan-07 10:43 
GeneralRe: Collections Pin
Craig G. Wilson21-Jan-07 15:50
Craig G. Wilson21-Jan-07 15:50 
GeneralRe: Collections Pin
LurkingVariable21-Jan-07 15:59
LurkingVariable21-Jan-07 15:59 
GeneralData Base Connectivity Pin
Fazal_qureshi17-Dec-06 22:39
Fazal_qureshi17-Dec-06 22:39 
GeneralRe: Data Base Connectivity Pin
Craig G. Wilson18-Dec-06 2:45
Craig G. Wilson18-Dec-06 2:45 
QuestionI receive the error: Parameter count mismatch Pin
klhkdsjhfksjhdfkjshf15-Nov-06 11:53
klhkdsjhfksjhdfkjshf15-Nov-06 11:53 
AnswerRe: I receive the error: Parameter count mismatch Pin
Craig G. Wilson15-Nov-06 12:01
Craig G. Wilson15-Nov-06 12:01 
GeneralRe: I receive the error: Parameter count mismatch Pin
Wilhelm Berg7-Feb-07 10:07
Wilhelm Berg7-Feb-07 10:07 
QuestionSource Pin
Wilhelm Berg7-Nov-06 8:32
Wilhelm Berg7-Nov-06 8:32 
AnswerRe: Source Pin
Craig G. Wilson7-Nov-06 8:35
Craig G. Wilson7-Nov-06 8:35 
It is in the demo site / app_code/DataTableAdapter.cs
AnswerRe: Source Pin
Wilhelm Berg8-Nov-06 6:38
Wilhelm Berg8-Nov-06 6:38 
GeneralRe: Source Pin
Craig G. Wilson8-Nov-06 6:56
Craig G. Wilson8-Nov-06 6:56 

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

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