views:

713

answers:

3

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?

+1  A: 

I typically do the dependency injection in the constructor like you have above, but take the lazy loading a step further by acting only when the "get" is called like I have below. Not sure if this is the pure approach you are looking for, but it does eliminate the "dirty" constructor DI/Lazy Loading in 1 step ;)

public class Product
{
    private int mProductID;
    private Supplier mSupplier;
    private ISupplierService mSupplierService;

    public Product()
    {
      //if you want your object to remain POCO you can use dual constr
      //this constr will be for app use, the next will be for testing
    } 

    public Product(ISupplierService SupplierService)
    {
        mSupplierService = SupplierService;
    }

    public Supplier Supplier {
        get {
            if (mSupplier == null) {
                if (mSupplierService == null) {
                    mSupplierService = new SupplierService();
                }
                mSupplier = mSupplierService.GetSupplierByProductID(mProductID);
            }
            return mSupplier;
        }
        set { mSupplier = value; }
    }
}
Toran Billups
Could be more elegant, but this is usually the implementation I have time for. It also leaves your code open to some higher-level library to handle lazy-loading by reflection, if you're in to that sort of thing.
ojrac
Same remark as above : Injecting services (and especially DAO) is not a good idea. It makes the object unusable without dependency, and make it very hard to test. It breaks badly persistence ignorance.
Think Before Coding
+1  A: 

I'm not terribly familiar with the term POCO, but the definitions I've read seem to generally follow the spirit of the object being independent of some larger framework.

That said, no matter how you slice it, if you're performing dependency injection, you're going to have collaborations with those classes whose functionality is injected in, and something that sticks the depended upon objects in, whether its a full blown injection framework or just some assembler class.

To myself it seems strange to inject a reference to an IOC container into a class. I prefer my injections to occur in the constructor with code looking something like this:

public interface IDao<T>
{
    public T GetById(int id);
}


public interface ICustomerDao : IDao<Customer>
{
}

public class CustomerDao : ICustomerDao
{
    public Customer GetById(int id) 
    {...}
}

public class Transaction<T> where T : class
{

    int _id; //Transaction always knows this value
    T _dataObject;
    IDao<T> _dao;

    public Transaction(IDao<T> myDao, int id)
    {
        _id = id;
        _dao = myDao;
    }

    public T Get()
    {
        if (_dataObject == null)
            _dataObject = _dao.GetById(_id);
        return _dataObject;
    }
}
Michael Lang
So you're basically saying that I should inject it through the constructor? Maybe, but seems awkward.
George Mauer
Injecting services (and especially DAO) is not a good idea. It makes the object unusable without dependency, and make it very hard to test. It breaks badly persistence ignorance.
Think Before Coding
+5  A: 

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

Think Before Coding