user351711
user351711

Reputation: 3301

How To Model Aggregates and Persist to Database in DDD

I am just trying to get out of my comfort zone of typical N-Tier architecture of Repository/Service/Presentation and have started looking at DDD with Aggregates and I have to admit I'm a little confused and was hoping someone could clarify the following example:

If I had an Entity called News, NewsImage and Customer which were all EF persist-able objects like so:

public class Customer
{
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
}

public class NewsImage
{
    public virtual int Id { get; set; }
    public virtual byte[] Data { get; set; }
    public virtual News News { get; set; }
}

public class News
{ 
    public virtual int Id { get; set; }
    public virtual string Name { get; set; }
    public virtual ICollection<NewsImage> NewsImages { get; set; }
    public virtual Customer Customer { get; set; }
}

As I understand it these could be the objects we would use to persist the domain objects to the database but if we are using aggregates from the domain model we could have something like this:

public class NewsAggregate
{
    public int Id { get; set; }
    public string Name { get; set }

    public void AddImageToNews(byte[] imageData)
    {
         // Hide NewsImage or that object and add the byte[] data here?
    }
}

My questions are following and I would appreciate any clarification as I am certain I am misunderstanding the fundamental principles here:

  1. Only the aggregate objects should be exposed to the presentation layer (or any consuming layer).
  2. How do I handle converting/persisting the aggregate objects to the database, I could use mapping which is fine but then how do I know if I am creating an object or updating (by whether it is transient if the Id is set or not?). How do I know if new images have been added and which to update or remove? I think the problem I am having is I call create pass a news aggregate to a Repository and create it, I could then get the aggregate back from the domain populated via the entities with EF and then add an image, when I pass the news aggregate back how do I know what has changed in order to create/update data?
    1. Where should the customer go, should it be on the news aggregate object as an AddCustomer method, should there be a CustomerAggregate which has an AddNews method and with both of these options how to persist?

Many thanks for any insight, I've been reading around and looking at sample projects which demonstrate the concept but don't seem to fully explain best ways to achieve this.

Upvotes: 2

Views: 3547

Answers (2)

eulerfx
eulerfx

Reputation: 37739

1) It depends on what capacity. There is a rule stating that aggregates can only reference other aggregates directly - not entities or value objects contained in other aggregates. This is to enforce aggregates as consistency boundaries - they fully encapsulate what they "aggregate". There should be a repository per aggregate. The presentation layer, and any outer layer, can require references to aggregates in two general capacities - for display purposes or for behavioral purposes. An aggregate shouldn't concern itself too much with how it will be displayed because queries can be implemented using a different model better suited for the task - a read-model. Instead, the aggregate should focus on behavior. And yes, in cases where the presentation layer wishes to execute a behavior on an aggregate it should reference the aggregate by its identity. Better yet, create an application service to encapsulate the domain layer and expose the behaviors as a simple facade.

Also, an aggregate is not a single class but usually a set of classes clustered around an aggregate root which is an entity. You don't necessarily need a separate class to represent the aggregate, it could just be the root entity.

2) For persistence, it seems you're using EF which should handle all change tracking for you. It should keep track of which objects are persistent or which are transient. ORMs such as NHibernate also do this.

2.1) This depends on whether Customer is itself an aggregate. If so, then News should reference Customer by ID only. Moreover, it may be that a customer is required for a news entity in which case a customer ID should be passed to the constructor of the News entity. If it is not required, then there is a behavior which associated a customer with a news entity. Consider this from the domain perspective - what is the meaning of associating a customer with a news entity? Try to move away from thinking in a technical, CRUD manner such as AddCustomer and think more in terms of the surrounding business intent.

As pointed out by Giacomo Tesio, DDD shows its value in domains with some complexity in business logic. If all your behaviors can be mapped to CRUD then leave it CRUD. Otherwise, look for behaviors in your domain instead of focusing on the data. Your entities and value objects should expose behaviors and hide state as much as possible. Do read and re-read the referenced article: Effetive Aggregate Design by Vaughn Vernon.

Upvotes: 2

Giacomo Tesio
Giacomo Tesio

Reputation: 7210

First: DDD does not suggest you any specific architecture. I've used many different architectures with DDD and you should use what's good for the task. Obviously, if you think in a data driven way, you will encounter many problems with DDD.

DDD is a methodology designed to cope with complex business rules. You should not use it if your application value is in technological asset (as being in the cloud, exposing web services or some nice html5/mobile UI), but in the complexity of the business that it handles.
You should not use DDD for simple business rules. The rule of thumbs is: if you don't need a domain expert to understand the business, you don't need DDD at all.

Then, to properly understand aggregates, you should read the Vernon's essay on the topic. That essay explain that aggregates exist to ensure business invariants. You should never use aggregates just to optimize db access.

Upvotes: 6

Related Questions