Comment traiter les objets de valeur dans le cadre D'Entity?
Comment puis-je maintenir la valeur des objets dans le cadre D'Entity sans polluer mon modèle de domaine? EF (Eh bien, DBS relationnel en général) me demander de définir une clé - que mes objets de valeur n'ont pas hors de la boîte, par exemple
public class Tag : ValueObject<Tag>
{
private readonly string name;
public Tag(string name)
{
this.name = name;
}
public string Name { get { return this.name; }}
}
d'un autre côté, Je ne devrais pas aborder les problèmes de persistance dans le modèle. Est-ce que je suis vraiment supposé créer une autre classe qui inclut tous les champs de l'objet value plus une propriété clé et ensuite les relier les uns aux autres? Je préfère pas.
Est-il peut-être une solution plus élégante?
2 réponses
Vaughn Vernon écrit sur les objets de valeur persistants (page 248) dans son excellent livre La Mise En Œuvre De Domain-Driven Design.
objets ORM et Single Value
l'idée de base est de stocker chacun des attributs de la valeur dans des colonnes séparées de la ligne où son entité mère est stockée. Autrement dit, un objet de valeur unique est dénormalisé dans la rangée de son entité mère. Il y a des avantages à employer la convention pour nom de colonne pour identifier clairement et normaliser la façon dont les objets sérialisés sont nommés.
ORM et de Nombreuses Valeurs Soutenu par une Base de données de l'Entité
une approche très simple pour maintenir une collection d'instances de valeur en utilisant un ORM et une base de données relationnelle est de traiter le type de valeur comme une entité dans le modèle de données. (...) Pour ce faire, nous pouvons employer un Supertype Layer.
Exemple de délimitée contextes en C# peut être trouvé ici: https://github.com/VaughnVernon/IDDD_Samples_NET
je travaille actuellement sur certains de ces défis. Je ne suis pas vraiment un fan de l'ajout D'un Id à votre base ValueObject<T>
class puisque cela donne un Id à tous les objets de valeur qu'ils soient nécessaires ou non, plus comme un objet de valeur par définition n'a pas D'Id, c'est tout ce qui hérite que le type de base ne sera plus un objet de valeur au sens pur.
avant d'aller plus loin, je voudrais noter qu'un concept clé dans le codage de DDD est que vous ne devez pas être pur DDD partout, juste si longtemps comme vous le savez, les concessions que vous faites et leurs compromis. Cela dit, votre approche peut certainement être considérée comme excellente, mais je crois qu'elle ajoute une concession qui n'est peut-être pas vraiment nécessaire. Cela a principalement une incidence sur l'égalité de vos objets de valeur. Avec l'ajout de l'Id, deux Balises, même avec le même nom ne sont plus égaux.
Voici mon approche de cette situation: D'abord le facile, pas vraiment applicable à ce que je pense que votre problème est, mais il est important. C'est l'objet de valeur unique dans la première partie de la réponse de Martin.
- faire de L'objet valeur une propriété D'une entité.
aussi longtemps que votre objet de valeur se compose de propriétés de type simples, le Framework Entity va cartographier cela très bien.
Par Exemple:
public class BlogEntry : Entity<Guid>
{
public String Text { get; private set; }
public Tag Tag { get; private set; }
// Constructors, Factories, Methods, etc
}
Entity Framework va gérer cela très bien, ce que vous allez finir avec est un BlogEntry de table simple qui se compose de tout simplement de:
- Id
- Texte
- Tag_Name
maintenant je me dis que ce n'est pas vraiment ce que vous cherchez dans ce cas, mais pour beaucoup d'objets de valeur ça marche très bien. Un objet de valeur de DateRange que j'utilise fréquemment est composé de plusieurs propriétés. Puis sur mes objets de domaine j'ai simplement une propriété du type DateRange. EF les place sur la table pour l'objet domain lui-même.
j'en parle parce que je retourne à la concession que nous avons faite d'ajouter Id à la ValueObject<T>
type de base, même si son Id ne peut pas être répertorié dans votre implémentation concrète d'objet de domaine, il est toujours là et sera tout de même repris par le Framework Entity qui pour cela, probablement le cas d'utilisation d'objet de valeur le plus commun ne fonctionne plus aussi bien.
OK, enfin, sur votre cas spécifique (que j'ai moi aussi rencontré quelques fois). Voici comment j'ai choisi de traiter la nécessité d'une entité contient une liste d'Objets de Valeur. En gros, ça revient à élargir notre compréhension du domaine. En supposant que L'objet de valeur de Tag est pour l'enregistrement de Tag dans un billet de blog, la façon dont je le regarde est qu'un billet de blog contient une liste de PostTag avec la valeur de Tag. Oui c'est une classe plus, mais vous n'avez pas besoin de l'ajouter pour chaque objet de valeur, il est uniquement nécessaire lorsque vous avez une liste d'objets de valeur, et je pense exprime mieux ce qui se passe.
Donc voici un exemple d'ajout d'une liste d'objet de valeur à un de l'entité (à l'aide de votre objet de valeur de la Balise ci-dessus):
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 };
}
}
qui va permettre à votre BlogEntry de contenir plusieurs tags sans compromettre les objets de valeur et Entity Framework va le mapper très bien sans avoir besoin de faire quoi que ce soit de spécial.