Sponsored By Aspose - File Format APIs for .NET

Aspose are the market leader of .NET APIs for file business formats – natively work with DOCX, XLSX, PPT, PDF, MSG, MPP, images formats and many more!

An ObjectDataSource/GridView Adapter for Business Entity Collections

Using ASP.NET 2.0’s new GridView control with the new ObjectDataSource allows you to properly layer your applications.  You can create strongly-typed collections of your business objects, and quickly bind them to the new Grid.  The hype sounds good.  Real good, in fact:

From Move Over DataGrid, There’s a New Grid in Town!

The GridView control is the successor to the DataGrid and extends it in a number of ways. First, it fully supports data source components and can automatically handle data operations, such as paging, sorting, and editing, provided its bound data source object supports these capabilities.

The key phrase here is “provided its bound data source object supports these capabilities” When you bind your GridView to an ObjectDataSource wired to a DataSet, DataView or DataTable, you do indeed get automatic sorting, and paging, and you can also filter your data through the ObjectDataSource’s FilterExpression property.  All this adds up to a really useful control, one that you can base your entire web applications around. 

Business Entities and SOA.

Okay, great. Well, say you’ve been using Business Entities and Strongly-Typed collections in lieu of DataSets to build your application framework and business layers.  If you’ve been developing this way, you’re probably a convert.  Having a nice, clean framework of entities can be a great foundation for application development.  You also may be using a service oriented pattern to return these entity objects, instead of filling your objects with an instance method of the business entity itself. 

Both of these patterns are good to follow, but neither work out very well using the ObjectDataSource.  If you’ve done this and you try wiring up these collections to an ObjectDataSource and GridView, you’ll find that a Strongly-Typed Collection doesn’t work with the filtering (setting the ObjectDataSource’s FilterExpression property) and automatic sorting capabilities of the GridView.  The GridView’s current implementation requires that you use a DataTable, DataSet or DataView, unless you want to handle these events yourself and do your sorting on your own.  It will automatically do paging, but other than that you’re on your own.

It also doesn’t like the service oriented/entity pattern much.  It actually works best when you have smart business objects that are DataTables, DataSets or DataViews and also implement methods which populate the entities.  In Fact, the ObjectDataSource’s control designer won’t complete until you specify which method on your business object is the “Fill” method. This is too bad, because often what we need is to be able to use our entity objects, our service tier methods, and a nice GridView that does the sorting/paging/filtering stuff easily. 

Since this doesn’t exist currently, the next best thing is to create a DataTable, fill it with your entity collection’s data, and hand this off to the GridView for presentation.  It’s a little strange having to go back to a DataTable after having built a nice clean framework of entities.  Whenever I find myself having to revert back to using DataSets or DataTables, just for the sake of using one control or another, I feel Michael Corleone in Godfather III –  “Just when I thought that I was out they pull me back in.” 

This is where I really can jibe with Jeffrey’s RAD Kills message.  We have this great RAD grid, but to use it you have to revert to a sometimes poor design choice (DataSets). 

The EntityDataTable – Best of Both Worlds?

To solve this problem of allowing my business entity collections to be quickly bind-able to a GridView I whipped together a quick abstract adapter class which I can sub-class that is actually a DataTable. This way, when I bind it to a GridView, it will support all this auto-sorting/filtering stuff.   This class has two methods, GetDataTable which uses reflection and returns a DataTable containing a column for each public property in my entity class.  It also contains an abstract method Fill which can be overridden to connect to your service tier, get your collection, and call the GetDataTable method with your collection and your collection’s contained type.

using System;

using System.ComponentModel;

using System.Data;

using System.Reflection;

 

public abstract class EntityDataTable : DataTable

{

 

    [DataObjectMethod(DataObjectMethodType.Select, true)]

    public abstract DataTable Fill(object parameter);

 

    /// <summary>

    /// Gets the data table.

    /// </summary>

    /// <param name=”list”>The list.</param>

    /// <returns></returns>

    protected DataTable GetDataTable(System.Collections.IList list, Type typ)

    {

        DataTable dt = new DataTable();

 

        PropertyInfo[] pi = typ.GetProperties();

        foreach (PropertyInfo p in pi)

        {

            dt.Columns.Add(new DataColumn(p.Name, p.PropertyType));

        }

 

        foreach (object obj in list)

        {

            object[] row = new object[pi.Length];

            int i = 0;

 

            foreach (PropertyInfo p in pi)

            {

                row[i++] = p.GetValue(obj, null);

            }

 

            dt.Rows.Add(row);

        }

 

        return dt;

    }

}

EntityDataTable in Action

Here’s a quick example of a derived class, that adpts my SomethingCollection to easily work with the GridView and ObjectDataSource.

    public class BindableSomethingCollection : EntityDataTable

    {

        public override DataTable Fill(object parameter)

        {

            SomeService somesrv = new SomeService();

            return GetDataTable(somesrv.GetSomeCollection(parameter as SomeType), typeof(SomeContainedType));

        }       

    }

And here’s a quick ASCX control snippet that shows it all tied together:


<asp:GridView ID =”GridView1″ runat=”server” AutoGenerateColumns=”True” EmptyDataText=”No Records” ShowFooter =”True” AllowPaging =”True”  AllowSorting=”True” DataSourceID=”ObjectDataSource1″ ></asp:GridView>


<asp:ObjectDataSource ID=”ObjectDataSource1″ runat=”server” SelectMethod=”Fill” TypeName=”BindableSomethingCollection”>
  <SelectParameters>
    <asp:SessionParameter DefaultValue=”null” Name=”parameter” SessionField=”PARAMETER” Type=”Object” />
  </SelectParameters>
</
asp:ObjectDataSource>

All that’s left for me to do is pop my parameter in the session, and call GridView1.DataBind().. Voila!  My grid is bound to my entity collection, sorting and paging work like a charm, and I can filter my data buy calling by setting the Filter parameter of the ObjectDataSource.

[tags: ASP.NET, .NET, C#]

About Brendan Tompkins

Brendan runs CodeBetter.Com. He was twice awarded MVP for Microsoft .NET, and is a founder and the CTO of Quick180.Com More about Brendan at https://www.linkedin.com/codebetter
This entry was posted in Uncategorized. Bookmark the permalink. Follow any comments here with the RSS feed for this post.