Re: DDD and aggregate roots
well, normally... at least in the occasions where I've dealt with roles and users... I've never added roles to users... but rather the other way around... add a user to a role. The role isn't a property of the user... the user is a property of the role... it could be a matter of semantics... but in every case where I've dealt with things like this, that is how it's been.
So I'd have an AddUser method in the Role class.... that would then add the user to the list of users maintained by the role internally...
-tg
Re: DDD and aggregate roots
Yes, I also thought of that and had some hesitation to it but, for this example, I am really looking at if using a method of the aggregate root (assume User is in this case) is the proper way to alter the underlying collection it is maintaining is correct.
My current understanding of using user.RoleIds.Add("1231"); would be considered a violation as you as circumventing the aggregate root to make changes to its child aggregate. This could also circumvent any possible business rules and the like. Would I be correct in this assumption?
Re: DDD and aggregate roots
Ok... now the question is a little clearer.... yes using User.RollIds.Add is bad ... which is why RoleIds should be private... for starters... then you have a read-only property that returns the collection (so you can iterate through it)....
so what you end up with is something like this:
Code:
public class User
{
public string Id { get; private set; }
public string Name { get; set; }
public string Username { get; set; }
private List<string> RoleIds;
public List<string> Roles
{
get { return RoleIds; }
}
//......
public void AddUserToRole(Role role)
{
RoleIds.Add(role.Id);
//Save updated user and role relationship to the database
}
}
Now the list of roles cannot be accessed directly... preventing direct edits to the collection... BUT... that just means you cannot do user.Roles.Add ... but you can still do user.Roles(0) = ""; so it doesn't affect the items in the colleciton, just the collection accessor itself.
-tg
Re: DDD and aggregate roots
To your first point, that is already accomplished with
Code:
public List<string> RoleIds { get; private set; }
It makes the set method internal to the class. BUT, your way gives me the notion that the get method should return a copy of the RoleIds instead of it actually returning the reference to the collection? EG RoleIds.ToList();...yea yea it is expensive, but perhaps a better way to make sure no changes are made to the underlying collection?
Re: DDD and aggregate roots
I think this is really an OO issue rather than a DDD one and you're absolutely correct.
Strictly speaking, if you want to expose the collection outside of the class you should expose a copy rather than the original (or a reference to it) because the class should be the only thing fiddling with it's private members. That said, for efficiency we'll often expose the reference and just assume that they won't be fiddled with outside of the class. If you're application has to be extremely performant you should probably stick with the reference, if not then a copy is a much better aproach. Nobody likes having their privates fiddled with (unless the fiddler is a Freind).
For that reason I personally dislike the 2010 syntax for properties. It muddies the line between the private and the public parts. I still prefer a proper private member and then a separate public property controlling access to it. It may be more verbose but it's clearer.
By the way, AddUserToRole should probably just be called AddRole. You're in the User class so mentioning the User in a method name is redundant, every method a class has should involve doing something to itself. And, yes, that does reveal me as an utter pedant but I do find that a strict naming convention for methods helps me think in the right way to keep their purpose nice and tight. If I ever spot a method that isn't either <verb> or <verb><noun> I start to question whether it's doing too much.