Wednesday, December 22, 2010

How to implement the Business Layer-I



The Database Model:
   The starting point for any application is the database model. This is the lowest tier and one of the most important. By developing a model which covers all your functional requirements, you build the foundations upon which your whole application relies.
Let's have a look at the database model for this sample application as our data layer is going to connect to it.
   As you can see, a Customer, can have several Orders. Each Orders item is related to one or more Order Details. Every Products item can be related to zero or more Order Details.
That's it. Not really complicated, but complex enough to demonstrate how to navigate through a set of interrelated tables.
Collecting the Business:
   If one thinks of any system, all we are really dealing with is collections of data. For instance, a list of customers is just a collection of customers. Each customer contains a collection of orders, which in turn contains a collection of order detail items.
   Within our business layer, for each major table or set of related tables, we will create a collection class based on the IList interface so that it can be used as a data source. Each Item within the collection will be an "Info" class which encapsulates the information for each table.
   So, for the Customer table in the example above, we will create two classes: CustomerInfoCollection and CustomerInfo which will encapsulate the collection and the detail respectively.
So we end up with this class model:
Not all that complicated, is it?
The next step is to see how these classes are implemented. We will base our collection class around the ArrayList object. It is not the most efficient option since casting to and from another type is relatively slow, but in order not to overcomplicate this implementation it is the most flexible one. For production use, I recommend you write your own or use some of the excellent classes referenced throughout the MSDN or related websites.
So, our basic class definition will look like this:

public class CustomerInfoCollection : IList
{
private ArrayList m_alCustomerInfo;

public CustomerInfoCollection()
{
m_alCustomerInfo = new ArrayList();
}
}

Code Snippet 1: CustomerInfoCollection Class and Constructor
Of course, we will need to implement IList. This can be done quite simply by encapsulating the ArrayList methods and making sure that only the required Info objects are added to it.
Here is a simple example which demonstrates an IList method which ensures that only CustomerInfo objects are added to the ArrayList:


public int Add(object value)
{
if (value is CustomerInfo)
{
return m_alCustomerInfo.Add(value);
}
else
throw new InvalidCastException("Collection only accepts CustomerInfo objects");
}

Interweaving the .NET Framework in our Business
   Well, this is a .NET article, so obviously we're going to leverage as much of the framework as we can. In part 1 of this series, I explained how the data layer would be responsible for communicating with the database or data source. The object resulting from this dialog is the DataSet. Once you realise that this object serializes to XML automatically, it becomes the obvious object to handle communication between the layers. Since it is independent of any data source, we do not compromise our layers.
   So, let's have a look at how we integrate the DataSet object into our classes.
If you look at Figure 2, we can set up a convenient relationship between the DataTable object by using it as a basic data store within the collection and using the DataRow within the Info class. Because the DataSet and not the DataTable is serializable, we will define a DataSet per collection and associate each DataRow with a specific Info item object.
So how will this look on implementation?

public class CustomerInfoCollection : IList
{
private ArrayList m_alCustomerInfo;
private DataSet m_ds;

public CustomerInfoCollection()
{
m_alCustomerInfo = new ArrayList();
}

public void GetAllCustomers()
{
// Instantiate a Data Layer class to fill the DataSet
// The specific method will fill a DataTable named "Customers"
// See Part 3 for further details.
DCustomers cust = new DCustomers();
m_ds = cust.SelectAllCustomers();

// Iterate on all rows and create an Info object per row
foreach (DataRow dr in m_ds.Tables["Customers"].Rows)
m_alCustomerInfo.Add(new CustomerInfo(this, dr));
}
}