DDD: Aggregates & Repositories

There has been a lot of discussion recently about how to handle aggregates that contain other aggregates when building models using DDD. The discussion started a couple weeks ago when Udi posted his proposed solution. Udi suggested that we should add a .Save() method to our domain object that does nothing other then fire an event that will allow any interested "parties" to catch the event and do the appropriate processing. I don't like the idea of adding methods to our domain objects that only fire events. Having a .Save() method on an object implies that calling that method will save the domain object to the data store. Additionally if we're following DDD we try to avoid adding data access like behavior to any of our domain objects. We leave the data access "logic" to our repositories. Let's quickly review the scenario that Udi presented (which came from a comment on one of my earlier DDD posts). We have a Customer object which has an associated address.

public class Customer {
   // ... other props...
   public Address Address {
     get { return _address; } 
     set { _address = value; }
   }
}

When we save the customer we also want to save the associated address. Now if we're following DDD we know that Repositories will play a large role in the saving of our domain objects. Each of our Aggregates should have a Repository that is responsible for handling all data related tasks for all the objects in the aggregate. If address is part of the Customer aggregate we have nothing to worry about since the CustomerRepository would then be responsible for saving the address itself. For arguments sake let's continue with the assumption that the Address class is the root of it's own aggregate and has it's very own Repository. How should the CustomerRepository handle the address when the customer is saved?

Since we're following DDD we should embrace the fact that we're going to be using repositories to save our domain objects.

public class CustomerRepository : DomainRepository {
   public bool Save(Customer customer) {
         SaveCustomerToDataStore(customer);
         AddressRepository addressRepository = new AddressRepository(); 
         addressRepository.Save(customer.Address); 
         return true;
    }
}

As Steve Maine pointed out in one of his follow up posts, including the AddressRepository directly in the CustomerRepository creates a dependency between our repositories that we don't want. What if all the sudden the address needs to be saved by a different repository? How do we introduce a mock address repository into the equation during testing? Rather then hard coding the repository, we should implement a RepositoryFactory class. The RepositoryFactory will have the responsibility of knowing what repository should be used for each type of domain object. The knowledge will either be provided during initialization, via a configuration file, or perhaps will be covered by a framework such as PicoContainer. By introducing a factory into our design we decouple the AddressRepository from the CustomerRepository.

public class CustomerRepository : DomainRepository {
     public bool Save(Customer customer) {
          SaveCustomerToDataStore(customer);
          DomainRepository addressRepository = RepositoryFactory.GetRepository(typeof(Address));
          addressRepository.Save(customer.Address); 
          return true;
      }
}

Since we may not always want to use the default RepositoryFactory we should use dependeny injection to allow users of the CustomerRepository to change the factory that is used.

public class CustomerRepository : DomainRepository {
    public CustomerRepository(IRepositoryFactory factory) {
      this.repositoryFactory = factory;
    }

    public IRepositoryFactory RepositoryFactory {
        get { return factory; }
    }

    public bool Save(Customer customer) {
       SaveCustomerToDataStore(customer);
       DomainRepository addressRepository = this.RepositoryFactory.GetRepository(typeof(Address));
       addressRepository.Save(customer.Address); 
       return true;
     }
}

With our constructor in place we can very easily inject the proper repository factory into our CustomerRepository. This will allow us to swap out our repository during the testing of our components and will allow us to keep our repositories decoupled, both good things. Next on the plate is the loading of our customer and its associated address, which will come in another post....

# re: DDD: Aggregates & Repositories

Monday, October 04, 2004 4:12 AM by David Hayden    
Hey Steve,

I am enjoying your posts on DDD. Is there a full example with code using DDD anywhere on the Internet, because I couldn't fine one.

Are these repositories calling data access crud methods that are in the objects? I am thinking your SaveCustomerToDataStore(customer) method is just doing a customer.Save() or doesn't the customer object contain data access code?

It is also interesting to see you making a separate call to save customer.Address. I would think customer should be responsible for saving it's children, because it needs to check the business rules to see if anything should be saved. Normally things would need to be added to a UnitOfWork and/or bound in a transaction.

I ordered the Eric Evans book, which should be here in a few days. Any chance you can post a short example with a little more code to enlighten us as to how these classes are organized and where exactly the data access code sits? Great stuff.

# re: DDD: Aggregates & Repositories

Monday, October 04, 2004 4:40 AM by Steve    
David, The examples I've been providing are definitely a little sparse and the code samples alone (at this point) leave a lot to be desired.

The repositories are not calling crud methods on the business objects, that is what the repositories sole purpose in life is for. I'll try and tie things together a little better in some future posts.

# re: DDD: Aggregates & Repositories

Wednesday, October 06, 2004 7:39 AM by Sanin Saracevic    
Comments in my blog:
<a target="_new" href="http://blogs.saninsaracevic.com/dotnet/archive/2004/10/06/373.aspx">http://blogs.saninsaracevic.com/dotnet/archive/2004/10/06/373.aspx</a>

#

Tuesday, April 05, 2005 6:32 AM by Confluence: Gentle.NET Community    
There is actually a pattern for this (from Eric Evans: Domain Driven Design). I believe it is referred to as Repository. This blog post touches on the pattern, although it is not a formal description of it:

# re: DDD: Aggregates & Repositories

Monday, October 15, 2007 3:53 PM by Fuzzelogic    
Hi!
I think there's an error in your final code block.
public class CustomerRepository : DomainRepository {
public CustomerRepository(IRepositoryFactory factory) {
this.repositoryFactory = factory; /// There is no repositoryFactory declared. Its factory (Property below)
}

public IRepositoryFactory RepositoryFactory {
get { return factory; }
}


OR did I miss something???

Post a Comment

 
 
Prove you're not a spammer: 
7 + 7 =