Active Record To Domain Objects and Data Access Objects - Data Access Design Patterns
by David Hayden ( Florida .NET Developer )
In my previous post
I discussed the fact that the Active Record Design Pattern doesn't require static finder methods for encapsulating common SQL queries to return one or more active record objects. One could move those static finder methods to a separate class, such as CustomerFinder, mentioned here again from the previous post:
public class CustomerFinder : ICustomerFinder
{
private IDatabase _database;
public CustomerFinder()
{
_database = DatabaseFactory.CreateDatabase();
}
public CustomerFinder(IDatabase database)
{
Validation.AssertIsNotNull(database);
_database = database;
}
public Customer FindById(int id)
{
...
}
public Customer FindByEmailAddress(...)
{
...
}
public CustomerCollection FindByState(...)
{
...
}
}
To each their own, but IMHO this is rather undesirable, because when a change occurs in the database we now need to change the persistence logic in 2 classes: 1) The Active Record Class which has read and write SQL capabilities, and 2) The Finder Class which handles SQL finder queries. You will also end up probably having 2 base classes or more (instead of a single layer supertype ) to refactor common code from the various active record and finder classes.
Data Access Objects
If static methods using active record is a problem, then the answer is not to go half-way and create Finder Classes, but to move to Data Access Objects (DAO). DAO does nothing more than separate the persistence logic for a class into a separate class. All persistent logic in the Active Record and Finder Classes gets moved to a class that is responsible for all data access needs for the class, leaving the original class with only data and domain logic behavior. The CustomerDAO Class doesn't look much differently from the CustomerFinder Class actually. It has just accepted additional behavior that was in the Customer Class:
public class CustomerDAO : ICustomerDAO
{
private IDatabase _database;
public CustomerDAO()
{
_database = DatabaseFactory.CreateDatabase();
}
public CustomerDAO(IDatabase database)
{
Validation.AssertIsNotNull(database);
_database = database;
}
public Customer FindById(...)
{
...
}
public int Save(Customer customer)
{
...
}
public int Update(Customer customer)
{
...
}
public int Delete(Customer customer)
{
...
}
public Customer FindByEmailAddress(...)
{
...
}
public CustomerCollection FindByState(...)
{
...
}
}
This is a trivial example and DAO objects will vary, but I think it shows the point. You will probably end up with a layer supertype for the domain layer and the data access layer for refactoring common code, etc:
public class CustomerDAO : DAOBase, ICustomerDAO
{
...
}
public class Customer : BusinessBase
{
...
}
Conclusion
If ActiveRecord Static Finder Methods are troublesome, you could create a Finder Class for each domain object. IMHO the effort is not worth the headache. Move to Data Access Objects and leave your domain objects persistent ignorant.
Source: David Hayden ( Florida .NET Developer )
Filed: Design Patterns