Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Populating custom business objects by binding business objects to a GridView using the ObjectDataSource in ASP.NET 2.0

0.00/5 (No votes)
20 Jan 2006 1  
A complete article on how to populate custom business objects using a common method, binding these objects to a GridView using the ObjectDataSource control.

Introduction

This article explains how to load custom business objects and bind them to a GridView. Only one common method is required for loading all business objects. I used a simple attribute class to map data from a database field to an object property. The container for business objects is a generics list. For now, I want to keep it simple. In future, I want to extend the functionality and make it more scalable. This project uses the following new features in .NET 2.0:

  • Loading a DataTable from a DataReader.
  • Obtaining the ConnectionString section from web.config.
  • Generics.
  • The ObjectDataSource control.

Solution walkthrough

This solution contains two projects. The first project (class library) explains how to populate custom business objects from database records. The second project (website) explains how to bind custom business objects to a GridView using an ObjectDataSource control. For demo purposes, I used the "AdventureWorks" database which ships with SQL 2005.

Populate Custom Business Objects (Project: AWBusinessObjects)

This project contains a database helper class, a custom attribute class, a business objects base class and two sample business objects.

Database Helper Class: DBHelper.cs

It is useful for loading data from a database to a disconnected DataTable using a DataReader. This feature is introduced in .NET 2.0. The ConfigurationManager of System.Configuration is used to get the database connection information from the web.config file.

class DBHelper
{
    private string strConn;
    private SqlCommand dbCmd;
    private SqlConnection dbConn;
    private SqlDataReader dbReader;
    private DataTable dbTable;
    //Constructor

    public DBHelper()
    {
        ConnectionStringSettings settings = 
          ConfigurationManager.ConnectionStrings["DBConn"];
        if (settings != null)
        {
            strConn = settings.ConnectionString;
        }
    }
    //Retrieve Data

    public DataTable RetrieveTable(string pSqlText)
    {
        try
        {
            dbTable = new DataTable();                
            dbConn = new SqlConnection(strConn);
            dbCmd = dbConn.CreateCommand();
            dbCmd.CommandText = pSqlText;                
            dbConn.Open();
            dbReader = dbCmd.ExecuteReader();
            if (dbReader != null && dbReader.HasRows)
            {
                dbTable.Load(dbReader);
            }
        }
        finally
        {
            dbConn.Close();
        }
        return dbTable;
    }
}

Attribute Class: MapInfo.cs

It defines the information to map data from a database field to a business object property. Nothing special here. It contains two fields. This attribute can be used at class level, or at property level, or at field level. AllowMultiple controls whether the attribute is multi-use.

[AttributeUsage(AttributeTargets.Class | 
     AttributeTargets.Property | 
     AttributeTargets.Field,AllowMultiple=true)]
class MapInfo: System.Attribute
{
    private string dbFieldName;
    private string objPropertyName;   
    public MapInfo(string pDBFieldName, 
                   string pObjPropertyName)
    {
        dbFieldName = pDBFieldName;
        objPropertyName = pObjPropertyName;
    }    
    public string DBFieldName
    {
        get { return dbFieldName;}
    }
    public string ObjPropertyName
    {
        get { return objPropertyName;}
    }    
}

Base Class for Business Objects: AWBase.cs

This contains the common method for populating inherited business objects. Reflection is used here for getting custom attributes and properties. It loops through all rows in a DataTable and sets property values using a custom attribute array. A generic list of the base class type is used as the container for the business objects. If the database value is DBNull then null is used as the property value.

public abstract class AWBase
{
    protected string SqlSelectString;
    protected Type BusObjectType;          
    protected List<AWBase> LoadData()
    {
       List<AWBase> _list = new List<AWBase>();
       DBHelper dbHelper = new DBHelper();
       //Get Data 

       DataTable dtBusinessObject = 
          dbHelper.RetrieveTable(SqlSelectString);
       //Custom Attributes

       object[] attributes = 
         BusObjectType.GetCustomAttributes(typeof(MapInfo), false);
       //Loop through all records in Table

       if (dtBusinessObject != null && dtBusinessObject.Rows.Count > 1)
       {
           for (int introw = 0; introw < 
                dtBusinessObject.Rows.Count; introw++)
           {
               AWBase busObject = 
                 (AWBase)Activator.CreateInstance(BusObjectType);
               //loop through all custom attributes

               for (int i = 0; i < attributes.Length; i++)
               {
                   MapInfo mapinfo = (MapInfo)attributes[i];
                   object DBValue = 
                     dtBusinessObject.Rows[introw][mapinfo.DBFieldName];
                   PropertyInfo pinfo = 
                     BusObjectType.GetProperty(mapinfo.ObjPropertyName);
                   pinfo.SetValue(busObject, DBValue.GetType() 
                     == typeof(DBNull) ? null: DBValue, null);
               }
               _list.Add(busObject);
           }
       }
       return _list;
    }       
}

Business Object: Product.cs

It is a sample class for business objects. This class will be populated from the "Production.Product" table. It has mapping information and public properties. The "GetProducts" method returns a generic list of products. Later, this method is used as SelectMethod in the ObjectDataSource control. For converting a base class to a child class, the generics ConvertAll function is used. Typically, all business objects contain mapping information, public properties, a select method, and an explicit casting method:

//Mapping Information

[MapInfo("ProductID", "ID")]
[MapInfo("Name", "Name")]
[MapInfo("ProductNumber", "Code")]
public class Product : AWBase
{
    private int id;
    private string name;
    private string code;
    ... 
    //Properties    

    public int ID
    {
        get { return id; }
        set { id = value; }
    }    
    public string Name
    {
        get { return name; }
        set { name = value; }
    }    
    public string Code
    {
        get { return code; }
        set { code = value; }
    }    
    ....
    //explict casting

    public Product AWBaseToProduct(AWBase pAWBase)
    {
        return (Product)pAWBase;
    }
    //Get Products

    public List<Product> GetProducts()
    {
        base.SqlSelectString = 
          "select * from Production.Product";
        base.BusObjectType = this.GetType();        
        List<AWBase> list = base.LoadData();
        return list.ConvertAll<Product>(new 
          Converter<AWBase,Product>(AWBaseToProduct));
    }
}

The "GetContacts" method in the Contact business object would look like:

public List<Contact> GetContacts()
{
    base.SqlSelectString = "select * from Person.Contact";
    base.BusObjectType = this.GetType();
    List<AWBase> list = base.LoadData();
    return list.ConvertAll<Contact>(new 
      Converter<AWBase,Contact>(AWBaseToContact));        
}

Bind a Generic list of business objects to a GridView (Project: AWDemo)

No written code is necessary here. Just dragging and configuring controls. I am giving here, the steps in order:

  • Create a new website.
  • Add a Reference to the previously created project.
  • Drag the "ObjectDataSource" control to the web page.
  • Select TypeName and SelectMethod from the data source configuration wizard.
  • Drag the "GridView" control to the webpage.
  • Set the DataSourceID.
  • Configure the paging properties and the GridView fields.

The code in the aspx page looks like this:

<asp:GridView id="GridView1" runat="server" 
        CellPadding="4" GridLines="None" ForeColor="#333333" 
        DataSourceID="ObjectDataSource1" 
        AutoGenerateColumns="False" AllowPaging="True" 
        PageSize="20" AllowSorting="True" 
        EmptyDataText="No Products Found">
    <FooterStyle BackColor="#1C5E55" 
        Font-Bold="True" ForeColor="White"  />
    <Columns>
        <asp:BoundField DataField="ID" 
          HeaderText="ID" ></asp:BoundField>
        <asp:BoundField DataField="Name" 
          HeaderText="Name" ></asp:BoundField>
        <asp:BoundField DataField="Code" 
          HeaderText="Code" ></asp:BoundField>
        <asp:CheckBoxField DataField="Finished" 
          HeaderText="Finished" ></asp:CheckBoxField>
        <asp:BoundField DataField="Size" 
          HeaderText="Size" NullDisplayText="N/A">
        </asp:BoundField>
        <asp:BoundField DataField="Cost" 
          HeaderText="Cost" NullDisplayText="N/A">
        </asp:BoundField>
        <asp:BoundField DataField="Color" 
          HeaderText="Color" NullDisplayText="N/A">
        </asp:BoundField>
        <asp:BoundField DataField="ModifiedDate" 
          HeaderText="ModifiedDate">
        </asp:BoundField>
    </Columns>
    <RowStyle BackColor="#E3EAEB"  />
    <EditRowStyle BackColor="#7C6F57"  />
    <SelectedRowStyle BackColor="#C5BBAF" 
       Font-Bold="True" ForeColor="#333333"  />
    <PagerStyle BackColor="#666666" 
       ForeColor="White" HorizontalAlign="Center"  />
    <HeaderStyle BackColor="#1C5E55" 
       Font-Bold="True" ForeColor="White"  />
    <AlternatingRowStyle BackColor="White"  />
</asp:GridView>
<asp:ObjectDataSource ID="ObjectDataSource1" 
    runat="server" SelectMethod="GetProducts" 
    TypeName="Product"></asp:ObjectDataSource>

I hope I kept it simple, and hopefully you will find it useful.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here