The shorter version of the Question: "Is it ok to have a superclass, with 2 subclasses, one is an entity the other is a Value Object?"
To longer version:
T have a Team superclass. The Team has the Master, Helpers and a Code.
Then i have the DefaultTeam, subclass of Team, which is an entity with an unique **Code**** has its domain identity.
Then i have the **ExecutionTeam, its a subclass of Team and has an extra attribute OriginalTeam:
public abstract class Team{
public string Code{ get; protected set; }
public Worker Master{ get; protected set; }
public IList<Worker > Helpers { get; protected set; }
...
}
public class DefaultTeam: Team
{
}
public class ExecutionTeam : Team
{
public virtual string Code { get { return OriginalTeam.Code; } }
public virtual DefaultTeam OriginalTeam { get; private set; }
...
}
The ExecutionTeam, is the team that executes a Task.
When a Task needs to be executed, we choose a DefaultTeam to execute it.
But we can change the Helpers from the DefaultTeam (the master never changes).
That team that executes the task, is a variation of the DefaultTeam (OriginalTeam), but with the Helpers that were chosen just for that Task.
The ExecutionTeam will have the same code has the OriginalTeam. So the ExecutionTeam has no unique identity.
If there are 10 executions of tasks by the same DefaultTeam, there will be 10 ExecutionTeams with the same code (with the same OriginalTeam). So ExecutionTeam is cannot be an Entity.
But having an Entity and a Value Object sharing the same superclass (both being Teams), is a bit strange. Maybe this domain model has something wrong.
Need opinions.
Thanks
What is it that makes the DefaultTeam a Value Object rather than an Entity? Isn't a DefaultTeam also an entity?
That being said, here are some comments:
Why do you need a special class for DefaultTeam? Can't a DefaultTeam simply be an ExecutionTeam, with certain specified values?
A DefaultTeam should probably be an instance of a Team that is associated with an application domain. For example, you might have a particular team that is generally used to solve problems with Project XYZ.
Instead of listing "DefaultTeam" as a property of the ExecutionTeam, you should probably have a "PreviousTeam" as a property of both the Team and ExecutionTeam classes.
This will be more generalizable, in case the team gets changed yet again.
Since Task is an important part of the domain and is assigned to a Team, it should probably be a property of Team.
"Helpers" doesn't seem an appropriate name for the team members. Why not just name them "Members" or "TeamMembers"?
"Master" is probably un-PC unless you are working in Dilbert land or dealing with a database :) You might want to change this to "Supervisor" or "Manager".
"Code" is probably a bad name in the context of your application, as it may easily be confused with programming code. You might want to use "Id" or "TeamId" instead.
Sounds like ExecutionTeam might be better modeled as an interface ICanExecuteTasks. Would that work for you? It would eliminate the issue you are struggling with..
As to your short question, if the ExecutionTeam was indeed a derived class of Team, (inheriting from team and representing an "IsA" relatoonship, then the answer is No, they cannot be of different types because of course, every ExecutionTeam isA Team, thgere is only one thing, which is both a Team and an ExecutionTeam at the same time... It cannot be both an entity Type and a value type at the same time.
But the way you have designed the classes, as you have structured things, ExcecutionTeam is not a derived class, it is a property of the DefaultTeam. This implies that they have a "HasA" relationship. THis implies that they are different, co-existing objects, one of which can be an entity and one of which can be a value type. But my gut tells me this is not an accurate mirror of your real domain model...
Related
Regarding below excerpt, concerning cqrs and ddd, from Patterns, Principles, and Practices of Domain-Driven Design by Nick Tune, Scott Millett
Does it mean that domain model on command side can omit most of business attributes ?
How would it look like for eg Customer Entity?
Could Customer entity omit FirstName, Surname etc?
If so, where would these business attributes be? Only in read model in CustomerEntity?
Or maybe apart from CustomerEntity containing all business attributes there would also be CustomerAggregate wrapping CustomerEntity with 1:1 relation, and command object would operate on CustomerAggregate? (seems strange to me).
What does it mean "Customer entity desn't make sense"?
The text you pointed means that you do not have to model a reusable Entity for your whole system or even for your whole bounded context (Do not model reusable real life things). Doing this is a bad design.
You have to model an Aggregate that performs an action. You feed the Aggregate with only, and just only, the data needed to perform that action and the aggregate response, the changes the domain suffered, is what you have to persist.
Why Entities and V.O.'s then?
To model consistency, encapsulation and decoupling is the basic part but these are implementation details. For DDD what matters is that are different roles (or concepts).
When feeding the aggregate (constructor, function call parameters, etc) the aggregate has to know if it is working with entities and/or with V.O. to build its response.
If the domain action means a change in an attribute of a entity (something with unique identification in your whole system) the response of the aggregate (once all rules and invariants has been checked) should include the new attribute value and the identification of that entity that allows persist the changes.
So, by default, every aggregate has its own entity with the unique identification and the attributes needed for the aggregate action.
One aggregate could have a Customer entity with ID and its Name.
Another aggregate could have a Customer entity with ID and its Karma points.
So every aggregate has its own inner Customer entity to work with. When you feed an aggregate you pass Customer data (i.e. ID and name or ID and Karma points) and the aggregate treats that info as a entity (It is a matter of implementation details if there is a struct, class, etc internally to the aggregate to represent the entity).
One important thing: If you just need to deal with entities ID's then treat it as a V.O. (CustomerIdentityVO) because the ID is immutable and, probably, in that action you just need to write this CustomerIdentityVO in some field in persistence, not change any Customer attribute.
This is the standard vision. Once you start to identify common structures relevant to several aggregates or one aggregate that can perform several actions with the same data fed you start to refactoring, reusing, etc. It just a matter of good OOP design and SOLID principles.
Please, note that I am trying to be higly above of implementation details. I know that you almost always will have unwanted artifacts that depends of programing paradigm type, chosen programing language, etc. but this approach helps a lot avoiding the worse artifact you could have.
Recommended readings:
http://blog.sapiensworks.com/post/2016/07/29/DDD-Entities-Value-Objects-Explained
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-1
http://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-2
https://blog.sapiensworks.com/post/2016/07/14/DDD-Aggregate-Decoded-3
and
https://blog.sapiensworks.com/post/2016/08/19/DDD-Application-Services-Explained
for a complete puzzle vision.
If you are using Event Sourcing then it's true that you can model aggregates without adding attributes that they don't need for implementing the business logic.
Here's an example:
class Customer {
public Guid ID { get; private set; }
public Customer(Guid id, firstName, lastName, ...) {
ID = id;
this.AddEvent(new CustomerCreatedEvent(id, firstName, ....);
}
public void ChangeName(firstName, lastName) {
this.AddEvent(new CustomerRenamedEvent(this.ID, firstName, lastName),
}
}
Custom only has ID attribute because it needs it to add it to every event that it generates. FirstName and LastName are omitted as they are not needed even when ChangeName method is called. It only records an event that this happened. If your logic requires the FirstName then you can add it. You can omit any properties that you don't need.
Your Repository in this case will save only the events and won't care about the values of the attributes of the Customer.
On the Read side you will probably need these properties as you will display them to your users.
If your aggregates are not event sourced, then you probably will need more attributes on your aggregate to implement it's logic and they will be saved to the database.
Here's an example:
class Customer {
public Guid ID { get; private set; }
public string FirstName { get; private set; }
public string LastName { get; private set; }
public void ChangeName(firstName, lastName) {
FirstName = firstName;
LastName = lastName;
}
}
In this case your Repository will need these properties as it will generate a query to update the database with the new values.
Not sure what "Customer entity doesn't make sense" means.
I am currently trying out DDD and reading Evans book. I have arrived at a model that has an aggregate whose root is Student. Now I need to have (or be able to distinguish) a RegisteredStudent and an EnrolledStudent (inherits RegisteredStudent). I don't know how to handle inheritance in DDD.
Should the 2 inherited classes be inside the aggregate? If so, are they also considered aggregate roots since their identity is the same as the root (there are only added properties to them)? If not, how do I give access to them from other entities?
Or should I not be using inheritance? Why?
And also, what if you have an entity in an aggregate that isn't a root, but you need it to inherit an entity outside? How should you go about it?
What you need to ask yourself here is whether a RegisteredStudent and an EnrolledStudent are different concepts. Are they not both students, but just in a different state?
In general, you should favor composition over inheritance.
Here's an example of what I would do. (Note that it's just my example, I don't know the domain, so it's not a definitive solution).
You could have a Student class, which is your aggregate root and then a few different state classes: Registered and Enrolled. That way you don't need to expose these state classes on the student but you could just expose methods on the Student. A small example in C#:
class Student
{
State _currentState;
void Enroll()
{
if(!_currentState is Registered)
throw new InvalidOperationException("Cannot enroll student who is not registered");
this._currentState = new Enrolled();
}
void Register(string name)
{
this._currentState = new Registered(name);
}
}
class StudentState{}
class Enrolled : StudentState
{}
class Registered : StudentState
{
public Registered(string name)
{
Name = name;
}
public string Name {get; private set;}
}
This is a simple application of the State design pattern, you could externalize more parts of it and build a complete state-machine, but I'll leave that up to you. (Also it's typed directly in to the SO-editor, so there could be syntax errors)
EDIT after comments
Whether you need to expose a State-property or not depends on the context. In general I would recommend not to do that, because you're exposing the internals of the Student. It would be better to expose a method called CanEnroll for example. That way you can change the internal implementation of your state pattern without affecting any clients.
As for question 3, it's hard to say without a use case. However, here are some guidelines:
Favor composition over inheritance (again, I know).
You can have a reference from inside an aggregate to the outer world, you shouldn't have a reference the other way around though.
I am using domain-driven design and I have a pretty clear picture of my domain model. It contains over 120 classes and it is quite stable. We will implement it in .NET 4 and C#. The thing is, we need the model to be multilingual; some of the attributes need to be stored in multiple languages. For example, the Person class has a Position property of type string which should store a value in English (e.g. "Librarian") and Spanish (e.g. "Bibliotecario"). The getter for this property should return the English or Spanish version depending on some language parameter.
And here begin my questions. I am not sure how to parameterize this. I have exlpored two major ways to do it:
Use property collections. Position would not be a string but rather a Dictionary<Language, string>, which would let clients retrieve the person's position by language.
Keep simple, scalar properties, but make them return (or set) the value for one language or another depending on a globally known "current language" setting. The client code would set the working language, and then all objects would set and get values in that language.
Option 1 avoids global state, but it messes up the interface of almost every class in my model. On the other hand, option 2 is less expressive, since you can't tell what language you're going to get without looking at the global setting. Also, it introduces a dependency into every class on the global setting.
Please note that I am not interested in database or ORM implementations; I am working at the domain model level only.
I have two specific questions then:
Which is the best option (1 or 2) to achieve my goal of a multilingual domain model?
Are there other options that I haven't considered, and which are they?
Thank you.
Edit. Some have suggested that this is a user interface related issue, and thus can be tackled through globalisation/localisation support in .NET. I disagree. UI localisation works only if you know the localised literals that must be shown to the user at compile time, but this is not our case. My question involves multilingual data that is unknown at compile time, because it will be provided as user data at run-time. This is not a UI-related issue.
Edit 2. Please bear in mind that the Person.Position is just a toy example to illustrate the question. It's not part of the real model. Don't try to criticise it or improve upon it; there is no point in doing that. Our business requirements involve a lot of attributes that cannot be encoded as enum types or similar, and must stay as free text. Hence the difficulty.
Given the following:
Some use case involve setting the values for an object in all the
supported languages; others involve looking at the values in one given
language.
I would suggest going for both options. That means that the Person and all classes that hold multilingual content should keep that content in their state and:
The Position property should set/get the person's position in the
current user's language.
There should be a corresponding property or method for all
language setting/getting.
There should be a method for setting (or even switching if needed)
the user language. I would create an abstract class (e.g.
BaseMultilingualEntity) with an abstract SetLanguage(Language
lang) method and a CurrentLanguage getter. You need to keep
track of all the objects that derive from BaseMultilingualEntity
in some sort of registry that would expose language setting.
EDIT WITH SOME CODE
public enum Language {
English,
German
}
// all multilingual entity classes should derive from this one; this is practically a partly implemented observer
public abstract class BaseMultilingualEntity
{
public Language CurrentLanguage { get; private set; }
public void SetCurrentLanguage(Language lang)
{
this.CurrentLanguage = lang;
}
}
// this is practically an observable and perhaps SRP is not fully respected here but you got the point i think
public class UserSettings
{
private List<BaseMultilingualEntity> _multilingualEntities;
public void SetCurrentLanguage(Language lang)
{
if (_multilingualEntities == null)
return;
foreach (BaseMultilingualEntity multiLingualEntity in _multilingualEntities)
multiLingualEntity.SetCurrentLanguage(lang);
}
public void TrackMultilingualEntity(BaseMultilingualEntity multiLingualEntity)
{
if (_multilingualEntities == null)
_multilingualEntities = new List<BaseMultilingualEntity>();
_multilingualEntities.Add(multiLingualEntity);
}
}
// the Person entity class is a multilingual entity; the intention is to keep the XXXX with the XXXXInAllLanguages property in sync
public class Person : BaseMultilingualEntity
{
public string Position
{
set
{
_PositionInAllLanguages[this.CurrentLanguage] = value;
}
get
{
return _PositionInAllLanguages[this.CurrentLanguage];
}
}
private Dictionary<Language, string> _PositionInAllLanguages;
public Dictionary<Language, string> PositionInAllLanguages {
get
{
return _PositionInAllLanguages;
}
set
{
_PositionInAllLanguages = value;
}
}
}
public class Program
{
public static void Main()
{
UserSettings us = new UserSettings();
us.SetCurrentLanguage(Language.English);
Person person1 = new Person();
us.TrackMultilingualEntity(person1);
// use case: set position in all languages
person1.PositionInAllLanguages = new Dictionary<Language, string> {
{ Language.English, "Software Developer" },
{ Language.German, "Software Entwikcler" }
};
// use case: display a person's position in the user language
Console.WriteLine(person1.Position);
// use case: switch language
us.SetCurrentLanguage(Language.German);
Console.WriteLine(person1.Position);
// use case: set position in the current user's language
person1.Position = "Software Entwickler";
// use case: display a person's position in all languages
foreach (Language lang in person1.PositionInAllLanguages.Keys)
Console.WriteLine(person1.PositionInAllLanguages[lang]);
Console.ReadKey();
}
}
A domain model is an abstraction - it models a specific part of the world, it captures the concepts of a domain.
The model exists so developers can communicate in code the way domain experts communicate - using the same names for the same concepts.
Now, a Spanish expert and an English expert may use different words for the same concept, but the concept itself would be the same (one hopes, though language can be ambiguous and people do not always understand the same concept in the same way, but I digress).
The code should pick one human language for these concepts and stick to it. There is absolutely no reason for the model to consist of different languages in order to represent a single concept.
Now, you may need to show users of the application data and meta data in their language, but the concept does not change.
In this regard, you second option is the thing you should be doing - with .NET, this is normally done by looking at the CurrentThread.CurrentCulture and/or CurrentThread.CurrentUICulture and by using satellite assemblies that will contain localized resources.
My question involves multilingual data
[...]
Please note that I am not interested in database or ORM
implementations;
I can see a bit of contradiction in these 2 statements. Whatever the final solution, you'll have multilingual-specific structures in your database anyway as well as a mechanism that queries them to do the translation, right ?
The thing is, unless your domain really is about translation, I would try to keep it away from multilingual concerns as much as possible, for the same reason that you would try to make your domain persistence ignorant or UI ignorant.
Thus I would at the very least place the multilingual resolution logic in the Infrastructure layer. You could then for instance use aspects to only attach multilingual behavior to some properties, if you really need a trace of multi-language in your entities and don't want your persistence layer to handle all that transparently :
public class Person
{
[Multilingual]
public string Position { get; set; }
}
It contains over 120 classes and it is quite stable.
Not directly related to question, but you might want to consider the existence of multiple bounded contexts in your domain.
I agree with Oded that it seems in your scenario, language is a UI concern. Sure, the domain may be declared via combination of C# and English, what it represents is abstract. The UI would handle language with CultureInfo.CurrentCulture - effectively option #2.
A Person entity having a Position property doesn't govern the natural language used to represent the position. You may have a use case where you'd want to display a position in one language while it is originally stored in another. In this case, you can have a translator as part of the UI. This is similar to representing money as a pair of an amount and currency and then converting between currencies.
EDIT
The getter for this property should return the English or Spanish
version depending on some language parameter.
What determines this language parameter? What is responsible for ensuring that, say Position, is stored in multiple languages? Or is translation to be performed on the fly? Who is the client of the property? If the client determines the language parameter, why can't the client perform the translation without involving the domain? Are there any behaviors associated with multiple languages or is this only a concern for reading purposes? The point of DDD is to distill your core behavioral domain and shifts aspects related to querying data into other areas of responsibility. For example, you can use the read-model pattern to access the Position property of an aggregate with a specific language.
Make the User explicit!
I already encountered domains where the user's culture is a first class citizen in the domain but, in such situations, I model a proper value object (in your example I would use a Position class properly implementing IEquatable<Position>) and the User that is able to express such values.
Sticking to your example, something like:
public sealed class VATIN : IEquatable<VATIN> { // implementation here... }
public sealed class Position : IEquatable<Position> { // implementation here... }
public sealed class Person
{
// a few constructors here...
// a Person's identifier from the domain expert, since it's an entity
public VATIN Identifier { get { // implementation here } }
// some more properties if you need them...
public Position CurrentPosition { get { // implementation here } }
// some commands
public void PromoteTo(Position newPosition) { // implementation here }
}
public sealed class User
{
// <summary>Express the position provided according to the culture of the user.</summary>
// <param name="position">Position to express.</param>
// <exception cref="ArgumentNullException"><paramref name="position"/> is null.</exception>
// <exception cref="UnknownPositionException"><paramref name="position"/> is unknown.</exception>
public string Express(Position position) { // implementation here }
// <summary>Returns the <see cref="Position"/> expressed from the user.</summary>
// <param name="positionName">Name of the position in the culture of the user.</param>
// <exception cref="ArgumentNullException"><paramref name="positionName"/> is null or empty.</exception>
// <exception cref="UnknownPositionNameException"><paramref name="positionName"/> is unknown.</exception>
public Position ParsePosition(string positionName) { // implementation here }
}
And don't forget documentation and properly designed exceptions!
WARNING
There are at least two huge design smells in the sample model that you provided:
a public setter (the Position property)
a System.String holding business value
A public setter means either that your entity exposes its own state to clients regardless of its own invariants, or that such a property has no business value for the entity and thus should not be part of the entity at all. Indeed, mutable entities should always separate commands (that can change the state) and queries (that cannot).
A System.String with business semantic always smells of a domain concept left implicit, typically a value-object with equality operations (that implements IEquatable, I mean).
Be aware that a reusable domain model is quite challenging to obtain, since it requires more than two domain experts and a strong experience in ddd modeling. The worst "domain model" that I faced in my carreer was designed by a senior programmer with huge OOP skills but no previous modeling experience: it was a mix of GoF patterns and data structures that, in the hope to be really flexible, proved to be useless. After 200k €, spent in that effort, we had to throw it away and restart from scratch.
May be that you just need a good data model directly mapped to a set of simple data structures in C#: you'll never have any ROI from an upfront investment in a domain model, if you don't really need it!
It might be worth mentioning Apache's MultiViews feature and the way it delivers different content based on the browser's Accept-Language header.
So if a user requests 'content.xml', for example, Apache will deliver content.en.xml or content.sp.xl or content.fr.xml or whatever is available based on some prioritization rules.
Given the requirements I would probably try to model the position as an entity/value on its own. This object would not be a dictionary of translations but rather just be usable as a key into a domainDictionary.
// IDomainDictionary would be resolved based on CurrentThread.CurrentUICulture
var domainDict = container.Resolve<IDomainDictionary<Position>>();
var position = person.Position;
Debug.Writeline(domainDict.NameFor(position, pluralForm: 1));
Now assuming you need to dynamically create new positions when a suitable synonym doesn't exist you could probably keep the data somewhat tidy by using the IDomainDictionary as an source for auto complete suggestions in the UI.
I'm developing an application using domain driven design. One of the patterns I've been using is Repository pattern. For the sake of simplicity, let's say I have following classes and interfaces.
Car - domain class representing car domain concept.
public class Car {
public int Id {get;private set;}
public string SomeUniqueCode {get;private set;}
}
ICarRepository - interface for adding, deleting or saving changes to Car objects.
public interface ICarRepository{
Car AddCar(Car c);
void DeleteCar(Car c);
}
My problem is, how to check uniqueness of SomeUniqueCode property among all Car objects in the database? That property is changed by user (not auto-generated) at any time during the object life-cycle. Of course, one solution would be to put the unique key in the database, but that is not the principle of DDD. I've seen Specification pattern used to validate single objects. How would that pattern be applied to a set of Car objects?
Is it legitimate that Specification class (let's call it CheckUniqueCarSpecification) accesses ICarRepository?
A repository mimics an in-memory collection. What I have used before is a Contains method as opposed to a Find method, I guess you could have either. A query layer could also be used for this. Just as you have a CarRepository you could have a CarQuery. Trying to check for uniqueness in the domain is somewhat pesky. I would do a check for the sake of convenience but still rely on the DB to raise the exception since you should also handle that case. Using the specification pattern for this may be more effort than it is worth.
Since repository is a 'collection' I wouldn't have Commit and Rollback on there.
Use DomainService ICarCodesLibrary.
public class Car {
ctor(string someUniqueCode, ICarCodesLibrary codes)
{
// the check
codes.IsValidCode(someUniqueCode)
}
public int Id {get;private set;}
public string SomeUniqueCode {get;private set;}
}
Implement the interface in the place where u create the Car object and inject it. Also get rid of the properties and use fields. The ID is OK to be a prop.
This is a long question so i am gonna go straight to the point. This is pseudo code for better illustration of the problem
DB Structure
User (UserID, Name, LastName)
Address(AddressID, UserID, Street, City, State, ZipCode) =>Many to One User relationship
Phone (PhoneID, UserID, Number, IsPrimary) =>Many to One User relationship
Domain Classes
class User:IEntity
{
public string Name {get;set;}
public string LastName {get;set;}
public ContactInfo{get;set;}
}
class Phone: IValueObject or IEntity? will see later.
{
public int id; // persistence ID, not domain ID
public string Number {get;set;}
}
class Address: IValueObject or IEntity? will see later.
{
public string Line1 {get;set;}
public string City {get;set;}
public string State {get;set;}
public string ZipCode {get;set;}
}
class ContactInfo: IValueObject or IEntity? will see later.
{
List<Address> Addresses {get;set;}
List<Phone> PhoneNumbers {get;set;}
}
So, so far we have a very basic representation of this domain and its models.
My question is the following. Let's say that i want to Update one of the addreses or fix the area code for one of the numbers because of misspelling wnen it was initially typed in.
If i follow Evan's bible about DDD, Value Objects should be immutable. Meaning, no changes to its properties or fields after it was created.
If that's the case, then i guess, none of my classes are a ValueObject, since i can't just recreate the whole ContactInfo class just because one portion of the string in the phone number is wrong. So, i guess that makes all my classes Entities?
Keep in mind that i have a "persistence id" for each of this classes since they are stored in a database.
Let's say that i decide to make Phone a value object, since it's easy to recreate in the constructor
public Phone(string newNumber)
so, it would be something like adding a method to User (agg root) AND contactinfo? (Demeter Law)
like...
User....
public void UpdatePrimaryPhoneNumber(string number)
{
this.ContactInfo.UpdatePrimaryPhoneNumber(number);
}
ContactInfo....
public void UpdatePrimaryPhoneNumber(string number)
{
var oldPhone = Phones.Where(p=>p.IsPrimary).Single();
var newPhone = new Phone(number, oldPhone.persistenceid???-> this is not part of the domain)
oldPhone = newPhone;
}
but i still have to deal with persistence id... grrrrr. what a headache.
Sometimes i feel when i read those blogs that most "ddd experts" that value objects are overused or i would say misused.
What would be the best solution to this scenario?
Thank you
If i follow Evan's bible about DDD, Value Objects should be immutable.
Meaning, no changes to its properties or fields after it was created.
If that's the case, then i guess, none of my classes are a
ValueObject, since i can't just recreate the whole ContactInfo class
just because one portion of the string in the phone number is wrong.
So, i guess that makes all my classes Entities?
While the VO itself may be immutable, a VO doesn't exist on its own - it is always part of an aggregate. Therefore, a VO can be immutable, but the object which references that VO doesn't have to be. What helped me understand VOs is to compare them to something like a primitive Int32 value. The value of each individual integer is immutable - a 5 is always a 5. But anywhere you have an Int32 you can set another value there.
For you domain, what that means is that you can have an immutable address VO, but a given use entity can reference any instance of an address VO. This is what will allow corrections and any other changes to be made. You don't change the individual fields on the address VO - you replace it with a whole new VO instance.
Next, "Persistence ids" shouldn't be expressed in anywhere in domain code. They exist solely to satisfy the needs of the relational databases and NoSQL databases don't require them at all.
The primary phone scenario should look more like this:
public void UpdatePrimaryPhoneNumber(string number)
{
var existingPrimaryNumber = this.Phones.FirstOrDefault(x => x.IsPrimary == true);
if (existingPrimaryNumber != null)
this.Phones.Remove(existingPrimaryNumber);
this.Phones.Add(new Phone(phoneNumber: number, isPrimary = true));
}
This method encapsulates the idea of updating an existing primary phone number. The fact that phone number VOs are immutable means that you have to remove an existing value and replace it with a new one. What usually happens on the database end, especially with ORMs like NHibernate, is it will issue a SQL delete and a subsequent insert to effectively replace all phone numbers. This is OK since the ID of the VOs doesn't matter.
An Entity has a rather unique and individual life-cycle. It has meaning when it stands alone.
The classic example of Order/OrderItem may help with this.
If an OrderItem becomes an Entity it would have a life-cycle of its own. However, this doesn't make too much sense since it is part of an Order. This always seems obvious when looking at an order but less so when looking at your own classes because there can be some references between classes. For instance, an OrderItem represents some Product that we are selling. A Product has a life-cycle of its own. We can have an independent list of Products. How we model the link between an OrderItem and the Product is probably another discussion but I would denormalize the Product data I require into the OrderItem and store the original Product.Id also.
So is the Address class an Entity or a Value Object? This is always an interesting one in that we have that favourite of answers: it depends.
It will be context-specific. But ask yourself whether you have (or need) an independent list of Addresss and then only have a need for the link to that Address in your User. If this is the case then it is an Entity. If, however, your Address makes sense only when it is part of your User then it is a Value Object.
The fact that a Value Object is immutable does not mean you need to replace more than just the specific Value Object. I don't know if I would have a ContactInfo class in your current design since it only wraps the two collections (Address/PhoneNumber) but I would keep it if there is more to it (probably is). So simply replace the relevant PhoneNumber. If you have something like primary/secondary then it is as simple as:
AR.ReplacePrimaryPhoneNumber(new PhoneNumber('...'))
If it is a list of arbitrary numbers then a Remove/Add would be appropriate.
Now for the persistence Id. You do not need one. When you have a primary/secondary scenario you know what your use case is and you can execute the relevant queries in your DB (to update the primary PhoneNumber, for instance). If you have an arbitrary list you may go for add all new numbers in my list and delete those numbers from the DB not in my list; else just delete all the numbers and add everything you have. If this seems like a lot of heavy movement: it is. Event sourcing would move a lot of this to in-memory processing and it is something I will be pushing for seriously going forward.
I hope this all makes sense. Getting away from focusing on the data side of things is rather difficult but necessary. Focus on the domain as though you have no database. When you find friction then do your utmost to not pull database thinking into your domain but try to think about ways you could keep your domain clean and still use your DB of choice.
I would create a class PhoneNumber which contains the String number of the current Phone class and use that as a Value object within your Phone class:
class Phone implements IEntity
{
public int id; // persistence ID, not domain ID
public PhoneNumber number {get;set;}
}
class PhoneNumber implements IValueObject
{
public String number {get;set;};
}
Later when your code evolves you will need (for example) phone number validation and you can put it in the PhoneNumber class. This class can then be reused over the whole application at different places.
The Address is in my opinion a Value object which you can treat like a whole. Although you could model Street, City, etc... which are normally entities, but this is probably over-modelling. No part of the address can change, the whole object is always replaced when changing after initial creation.
The User class is within this example with these boundaries an Aggregate root (and thus also an Entity).
The ContactInfo class is not a ValueObject (not immutable) and not an Entity (no real identity) but an Aggregate. It contains multiple classes which should be seen as a whole.
More info on http://martinfowler.com/bliki/DDD_Aggregate.html
Usually whenever a persistence id is there you should be thinking of an Entity.
If however you would want to add the persistence id's, I would start splitting like the Phone and PhoneNumber class. For example Address (Entity containing id) and AddressValue containing all the other fields (and logic about address values).
This should also solve the headache about managing the persistence identities, since you replace the whole value object and the persistence identity stays the same in case of the updatePrimaryPhoneNumber.