In an earlier post, we started with logic similar to this:
IDataReader dr;
try
{
dr = DAL.GetSomeData(filter);
while (dr.Read())
{
if ( dr["field"] != System.DBNull.Value)
{
DateTime convertedDate = Convert.ToDateTime(dr["field"].ToString());
}
if ( dr["nextField"] != System.DBNull.Value)
{
Double convertedDouble = Convert.ToDouble(dr["nextField"].ToString());
}
. . . .
catch (Exception ex)
{
// Handle exception
}
finally
{
dr = null;
}
}
And showed how to reduce the Complexity to something similar to this:
IDataReader dr;
try
{
dr = DAL.GetSomeData(filter);
while (dr.Read())
{
DateTime convertedDate = (DateTime) RetrieveDataFromDataReader (dr, typeof (DateTime), “field”);
Double convertedDouble = (Double) RetrieveDataFromDataReader (dr, typeof (Double), “nextField”);
. . . .
}
}
catch (Exception ex)
{
// Handle exception
}
finally
{
dr = null;
}
}
This is good in that it reduces the Complexity to be a constant instead of making it dependent on the number of fields being retrieved. We are also doing something nice worth pointing out. By using IDataReader instead of SQLDataReader or OracleDataReader, we have removed a direct tie to a particular database platform.
The problem comes in when business logic is dependent on the field names. This dependency in essence decentralizes the data mapping logic. Also, there is no compiler support for getting the field names right. If you get the name of the field wrong, you get a run time error instead of a compile time error. We prefer compile time errors. If the name of a field changes for any reason and this mapping logic is embedded with business logic, then there are multiple places that may need to be changed.
A better approach is to encapsulate this data mapping logic in a proxy object. Business logic is then written against this proxy object and can be oblivious to any data mapping changes. We bragged earlier that using an IDataReader we removed a direct dependency to SQLDataReader or OracleDataReader. By using a proxy object, we remove ourselves from the dependency that a database is even used.
If the proxy object exposes a strongly typed property for every field in the underlying data source, then the business logic can be implemented against them and never have to worry about data mapping logic or data type conversion logic. If the underlying data source changes, only the proxy object has to change. The business logic that was written against the proxy object stays the same.
With such a strong separation between the data access logic and business logic, the business logic won’t get lost in the “noise” of the data access logic. The mechanics of data type conversion and data mapping can be safely hidden away allowing the business logic to focus on business rules. This will make the business logic easier to follow, less likely to include bugs, and be more easily maintained.