What is the proper way to inject a data access dependency when I do lazy loading?
For example I have the following class structure
class CustomerDao : ICustomerDao
public Customer GetById(int id) {...}
class Transaction {
int customer_id; //Transaction always knows this value
Customer _customer = null;
ICustomerDao _customer_dao;
Customer GetCustomer() {
if(_customer == null)
_customer = _customer_dao.GetById(_customer_id);
return _customer
}
How do I get the reference to _customer_dao into the transaction object? Requiring it for the constructor seems like it wouldn't really make sense if I want the Transaction to at least look like a POCO. Is it ok to have the Transaction object reference the Inversion of Control Container directly? That also seems awkward too.
How do frameworks like NHibernate handle this?
I suggest something different... Use a lazy load class :
public class Lazy<T>
{
T value;
Func<T> loader;
public Lazy(T value) { this.value = value; }
public Lazy(Func<T> loader { this.loader = loader; }
T Value
{
get
{
if (loader != null)
{
value = loader();
loader = null;
}
return value;
}
public static implicit operator T(Lazy<T> lazy)
{
return lazy.Value;
}
public static implicit operator Lazy<T>(T value)
{
return new Lazy<T>(value);
}
}
Once you get it, you don't need to inject the dao in you object anymore :
public class Transaction
{
private static readonly Lazy<Customer> customer;
public Transaction(Lazy<Customer> customer)
{
this.customer = customer;
}
public Customer Customer
{
get { return customer; } // implicit cast happen here
}
}
When creating a Transcation object that is not bound to database :
new Transaction(new Customer(..)) // implicite cast
//from Customer to Lazy<Customer>..
When regenerating a Transaction from the database in the repository:
public Transaction GetTransaction(Guid id)
{
custmerId = ... // find the customer id
return new Transaction(() => dao.GetCustomer(customerId));
}
Two interesting things happen : - Your domain objects can be used with or without data access, it becomes data acces ignorant. The only little twist is to enable to pass a function that give the object instead of the object itself. - The Lazy class is internaly mutable but can be used as an immutable value. The readonly keyword keeps its semantic, since its content cannot be changed externaly.
When you want the field to be writable, simply remove the readonly keyword. when assigning a new value, a new Lazy will be created with the new value due to the implicit cast.
Edit: I blogged about it here :
http://www.thinkbeforecoding.com/post/2009/02/07/Lazy-load-and-persistence-ignorance
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With