Attualmente sto lavorando attraverso alcune di queste stesse sfide. Non sono davvero un fan di aggiungere un ID alla tua classe di base ValueObject<T>
poiché questo dà un Id a tutti gli oggetti valore se sono necessari o più come un oggetto valore per definizione non ha Id, è qualcosa che eredita quel tipo di base no più a lungo essere un oggetto di valore nel senso puro.
Prima di andare oltre, vorrei notare che un concetto chiave nella codifica di DDD è che non devi essere puro DDD ovunque, purché tu sappia quali sono le tue concessioni e i loro trade-off. Detto questo, il tuo approccio può sicuramente essere considerato valido, tuttavia credo che aggiunga una concessione che potrebbe non essere realmente necessaria. In primo luogo, questo influisce sull'uguaglianza dei tuoi oggetti valore. Con l'aggiunta di Id, due Tag, anche con lo stesso nome non sono più uguali.
Ecco i miei approcci a questa situazione: Prima il più semplice, non proprio applicabile a quello che penso sia il tuo problema ma è importante. Questo è l'oggetto a valore singolo nella prima parte della risposta di Martin.
- Rendi l'oggetto valore una proprietà di un'entità.
Fintanto che l'oggetto valore è costituito da proprietà di tipo semplice, Entity Framework eseguirà il mapping corretto.
Per esempio:
public class BlogEntry : Entity<Guid>
{
public String Text { get; private set; }
public Tag Tag { get; private set; }
// Constructors, Factories, Methods, etc
}
Entity Framework gestirà che bene, quello che finirà con è un singolo blogEntry tabella che consiste semplicemente di:
Ora immagino che in questo caso non sia quello che vuoi, ma per molti oggetti di valore funziona alla grande. Uno che uso frequentemente è un oggetto valore DateRange che consiste di diverse proprietà. Quindi sui miei oggetti di dominio ho semplicemente una proprietà del tipo DateRange. EF associa quelli alla tabella per l'oggetto dominio stesso.
Riporto questo perché torniamo alla concessione che abbiamo fatto di aggiungere Id al tipo di base ValueObject<T>
, anche se Id potrebbe non essere elencato nell'implementazione concreta dell'oggetto dominio, è ancora lì e verrà comunque prelevato da Entity Framework che, per questo, probabilmente il caso d'uso degli oggetti value più comune non funziona più altrettanto bene.
OK, infine, sul tuo caso specifico (che anch'io ho incontrato alcune volte). Ecco come ho deciso di gestire la necessità che un'entità contenga un elenco di oggetti valore. Fondamentalmente si riduce ad ampliare la nostra comprensione del dominio. Supponendo che l'oggetto valore Tag sia per la registrazione di Tag in un post del blog, il modo in cui lo guardo è che un BlogPost contiene un elenco di PostTag con il valore di Tag. Sì, è un'altra classe, ma non è necessario aggiungerla per ogni oggetto valore, è necessaria solo quando si ha una lista di oggetti valore, e penso che esprima meglio ciò che sta accadendo.
Così qui è un esempio di aggiungere un elenco di un oggetto di valore ad un ente (usando il vostro oggetto valore di Tag sopra):
public class BlogEntry : Entity<Guid>
{
public String Text { get; private set; }
public ICollection<PostTag> PostTags { get; private set; }
// Constructors:
private BlogEntry(Guid id) : base(id) { }
protected BlogEntry() : this(Guid.NewGuid()) { }
// Factories:
public static BlogEntry Create (String text, ICollection<PostTag> tags = null)
{
if(tags == null) { tags = new List<PostTag>(); }
return new BlogEntry(){ Text = text, Tags = tags };
}
// Methods:
public void AddTag(String name)
{
PostTags.Add(PostTag.Create(name));
}
}
public class PostTag : Entity<Guid>
{
// Properties:
public Tag Tag { get; private set; }
public DateTime DateAdded { get; private set; } // Properties that aren't relevant to the value of Tag.
// Constructors:
private PostTag(Guid id) : base(id) { }
protected PostTag() : this(Guid.NewGuid()) { }
// Factories:
public static PostTag Create(Tag tag)
{
return new PostTag(){ Tag = tag, DateAdded = DateTime.Now };
}
public static PostTag Create(Tag tag, DateTime dateAdded)
{
return new PostTag(){ Tag = tag, DateAdded = dateAdded };
}
}
che permettono al blogEntry di contenere più tag, senza compromettere gli oggetti di valore e Entity Framework lo mapperà perfettamente senza la necessità di fare nulla di speciale.
È possibile ereditare la classe e aggiungere la proprietà chiave alla classe derivata –
Ci ho pensato, ma mi piacerebbe comunque finire con 2 classi per oggetto valore. –