I am using a DDD-like approach for a greenfield module of an existing application; it's not 100% DDD due to architecture but I'm trying to use some DDD concepts. I have a bounded context (I think that's the proper term - I'm still learning about DDD) consisting of two Entities: Conversation and Message. Conversation is the root, as a Message doesn't exist without the conversation, and all messages in the system are part of a conversation.

I have a ConversationRepository class (although it's really more like a Gateway, I use the term "Repository") which finds Conversations in the database; when it finds a Conversation it also creates (via Factories) a list of messages for that Conversation (exposed as a property). This seems to be the correct way of handling things as there doesn't seem to be a need for a full-blown MessageRepository class as it only exists when a Conversation is retrieved.

However, when it comes to saving a Message, is this the responsibility of the ConversationRepository, since it's the aggregate root of Message? What I mean is, should I have a method on ConversationRepository called, say, AddMessage that takes a Message as it's parameter and saves it to the database? Or should I have a separate repository for finding/saving Messages? The logical thing seems to be one repository per Entity, but I've also heard "One repository per Context".

2 Answers
2

The blue book is definitely worth a read if you want to get the best out of the DDD approach. DDD patterns are not trivial and learning the essence of each of them will help you ponder when to use which pattern, how to divide your application in layers, how to define your Aggregates, and so on.

The group of 2 entities you're mentioning isn't a Bounded Context - it's probably an Aggregate. Each Aggregate has an Aggregate Root, an Entity that serves as a single entry point to the Aggregate for all other objects. So no direct relation between an Entity and another Entity in another Aggregate that is not the Aggregate Root.

Repositories are needed to get hold of Entities that are not easily obtained by traversal of other objects. Repositories usually contain Aggregate Roots, but there can be Repositories of regular Entities as well.

In your example, Conversation seems to be the Aggregate Root. Maybe Conversations are the starting point of your application, or maybe you want to query them with detailed criteria so they are not satisfyingly accessible through simple traversal of other objects. In such a case you can create a Repository for them that will give the client code the illusion of a set of in-memory Conversations to query from, add to or delete from directly.
Messages on the other hand are easily obtained by traversal of a Conversation, and you might not want to get them according to detailed criteria, just all of a Conversation's Messages at once, so they might not need a Repository.

ConversationRepository will play a role in persisting Messages, but not such a direct role as you mention. So, no AddMessage() on ConversationRepository (that method rather belongs in Conversation itself) but instead, each time the Repository will persist a Conversation, it's a good idea to persist its Messages at the same time, either transparently if you use an ORM framework such as (N)Hibernate, using ad hoc SQL if you choose so, etc.

You could create the ConversationService and inject the IConversationRepository and IMessageRepository in its constructor. Use repositories for simple CRUD operations, and services for everything else (caching, saving logic, etc.)