Recently I was involved in a discussion on creating BusinessObjects, BusinessObject Collections, and where one should keep the code to create the objects.

In a N-tiered system, you want to create seperate tiers. While most people can quote the name of the tiers, understanding them and actually keeping them seperated is the fall short area.

I have created a sample which has a:

Presentation Tier ( a Console App )

Business Tier.

DataLayer Tier.

I am piggy-backing off the NorthWind database for my example.

I have created 2 strong objects (Customer and Order), and 2 Collection objects (CustomerCollection and OrderCollection).

I have also created a CustomerController object to handle the creation of Customer’s and Order’s.

The CustomerController is a business object, which calls the DataLayer object, and gets an IDataReader to populate the data.

(Sql Server 2000/7.0/2005 scripts are included in the download as well).

I am also using the DAAB 2.0 "SQLHelper" class to assist with the datalayer object. While I use the EnterpriseLibrary project now in my production code, the SQLHelper is good for this demo, as it is Sql Server (2000 usually) specific. It also provides an easier mechanism for implementing the connection string property.

However, it points out the fact that I should be able to move from one DataHelper (SQLHelper) to another (EnterpriseLibrary.Data) and *never* have to touch/recompile the

Presentation Code or the

BusinessLogic Code

In fact, you could switch from Sql Server to Oracle, and never have to recompile these 2 upper tiers (again, Presentation and BusinessLogic should be isolated from the database vendor of choice)

Hopefully the sample will provide an illustration to avoid common mistakes.

Those mistakes are:

1. Intertwined business layer logic and database connectivity.

2. Substituting the SQLHelper class ~in place of~ the application’s DataLayer object. The SQLHelper (as the name implies) is there to assist/help the DataLayer object, not replace it.

I show how to create a sub collection of Orders per Customer, and how to accomplish this with one database call. (IDataReader.NextResult();)

I show how the DataAccessLayer should be simple, and pretty much return only data.

My rule of thumb is that:

The DataLayer object should return:

IDataReader’s

DataSet’s (typed and untyped)

Scalars ( count(*) is an example here)

void/Nothing (aka, you just call a stored procedure which does something, but does not return anything)

That’s it. That’s what the DataLayer should return.

The obvious reason is that any RDBMS or datastore should be able to return DataSet’s and IDataReaders. That’s the goal, to provide data to the business layer without having intricate knowledge of the backend database.

4 Responses to Custom Objects/Collections and Tiered Development

In my opninon, this is a good approch if ur presentation tier is going to call ur business tier less frequently. This is a classic Engine-Collection-Class design pattern but this has some problems.
First is performance. As everything is happing in memory, u need to have more memory. More u use the memory less the performace as less memory is available for some other processes.
Secondly, if the server hosting business tier crashes then ur memory is lost and so as the data.
Third, if u have farm at the business tier then it is difficult to maintain the state.
If above is not a implcit requirement then this is a good approch

HI,nice example, and explanation. Got a question, though:Your \’common mistake\’ number 3 states \’Keeping objects (their properties, methods and sometimes events) seperate from the code which creates them\’I wonder exactly why you say this is a mistake? If my object wants to persist itself in a database, then \’populating itself\’ from, say, a DataRow would seem like a good idea, to me.Am I missing some good reason for not doing this?

Because you are assuming the Business Object will always be coming to/from a DataRow. Microsoft changes its database access technology every 2.5 years I think (see Rocky "The CSLA guy" for this stat). So while today it makes sense, one day your object may not be coming from a DataRow.Another reason is serialization (like wcf). You want to keep your objects POCO simple, so that when they go across the wire they are as small as possible.