views:

130

answers:

3

Say we have two aggregate roots in a domain model: Group and User.

Now, Users can be added to or removed from groups. Using the repository pattern, I only modelled the following two interfaces so far:

interface IGroupRepository
{
    Group FindById(int groupId);
}
interface IUserRepository
{
    User FindById(int userId);
    IQueryable<User> GetGroupMembers(int groupId);
    void AddUserToGroup(User user, Group group);
    void RemoveUserFromGroup(User user, Group group);
}

Somehow, the doesn't feel right. I want to achieve a clean domain model and not end up with a mere data-access layer. What would be a better way to model the above?

EDIT: The root question here seems to be, is it OK with DDD's guidelines to treat User as a 'sub-object' while it at the same time is an aggregate root as well? As I understood DDD, it states that aggregate roots must only be retrieved and stored from one place (the repository) so that's why I get a bit confused.

+2  A: 

If you use a ORM such as NHibernate to it's full potential you can have methods like this:

class Group
{
    List<User> members;

    void Join(User user)
    {
        members.Add(user);
    }

    void Leave(User user)
    {
        members.Remove(user);
    }
}

A decent ORM will track the changes to the members list and persist those to the database.

This would enable your interfaces to be simplified to:

interface IGroupRepository
{
    Group FindById(int groupId);
}

interface IUserRepository
{
    User FindById(int userId);
}

This should give you some guidance on doing this with NHibernate.

Garry Shutler
NHibernate info can now be found at http://nhforge.org/ - the older site has been down for a while now
Steve Willcock
Isn't this approach treating User as not being an aggregate root? I am confusedbtw, I don't care about persistance just yet - just looking for the general design pattern
JacobE
Sort of. If you only consider this situation then it probably isn't an aggregate root. However, I'm assuming you'd use the User for much more. The only reason to have a repository is as a way of persisting (mostly). So imagine how you'd model it without the repository first.
Garry Shutler
A: 

It is ok for the domain model to be close to the data-access layer. If it wasn't than you probably have a problem (with the database design). The idea of separating the domain model is to have good separation which in turn will give you more freedom. It is and not just to be different...

You will still have your data-access layer, but the domain model will be very simple (just propagating calls).

Bojan Milenkoski
I got even more confused by your answer
JacobE
+1  A: 

In this case I would consider creating a collection of Groups on the User or vice versa. That way you do not need a specialized method on the repository. Most ORM frameworks support this kind of mapping

public class User
{
    public virtual ICollection<Group> Groups {get;set;}
}
Dries Van Hansewijck
The core question seems to be if it breaks the consistency of the domain model to treat User as a 'sub-object' when it is in fact an aggregate root. Gonna edit the question a bit
JacobE
After thinking more about it, it DOES seem natural to have a Users collection on a Group. It should maybe just be perceived as a list of references to the aggregate root instances
JacobE