Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to avoid persisting entire aggregate root when adding child entity?

I have a domain model with an aggregate root:

public interface IAggregateRoot {
    public string Id { get; }

    public string Foo { get; set; }
    public int Bar { get; set; }

    public IList<IChildEntity> Children { get; }
}

The Children collection tends to get very large and I will be lazy loading it when an IAggregateRoot instance is retrieved through the IAggregateRootRepository. My problem is this; if I want to add an IChildEntity to an IAggregateRoot's Children collection, how can my repository allow me avoid persisting the entire aggregate?

For example, let's say my IAggregateRootRepository were to look like the following:

public interface IAggregateRootRepository {
    public IAggregateRoot GetById(string id);

    public void AddOrUpdate(IAggregateRoot root);
}

Then I could add to the Children collection by getting an IAggregateRoot instance through IAggregateRootRepository.GetById(), adding the child to the Children collection, then persisting it all through IAggregateRootRepository.AddOrUpdate(). That would, however, persist the entire aggregate root, along with its massive collection of children, every time I add a child entity. I guess I could get around that if my repository looked like:

public interface IAggregateRootRepository {
    public IAggregateRoot GetById(string id);

    public void AddOrUpdate(IAggregateRoot root);
    public void AddOrUpdate(IChildEntity child);
}

But, as I have understood the repository pattern, a repository should only deal with aggregate roots and the solution above certainly breaks that requirement.

Are there other, better, ways of avoiding this problem?

like image 413
David Nordvall Avatar asked Dec 16 '11 10:12

David Nordvall


1 Answers

Aggregate roots should be designed around write boundaries - that is, anything that typically gets written to the database in a single batch/transaction. If you're finding that you need to individually persist child entities which aren't roots, it might be time to reconsider your design, and make your child entity a distinct aggregate root itself (since it has a separate write boundary).

Your original aggregate root would then not contain the child entities, but rather references to them (as they are now aggregate roots themselves - and links between aggregate roots should be via reference keys). This would help with your lazy loading strategy also.

Hope that helps :)

like image 194
MattDavey Avatar answered Oct 03 '22 21:10

MattDavey