Question

C’est une question pratique de Domain Driven Design:

Sur le plan conceptuel, je pense obtenir des racines agrégées jusqu’à ce que j’en définisse un.

J'ai une entité Employé, qui est apparue sous la forme d'une racine agrégée. Dans l'entreprise, certains employés peuvent se voir enregistrer des violations liées au travail:

Employé ----- * Violations

Puisque tous les employés ne sont pas soumis à cela, je penserais que les violations ne feraient pas partie de l’ensemble des employés, n’est-ce pas?

Ainsi, lorsque je souhaite travailler avec des employés et les violations associées, s'agit-il de deux interactions distinctes du référentiel par un service?

Enfin, lorsque j’ajoute une violation, cette méthode s’applique-t-elle à l’entité salariée? Merci pour l'aide!

Était-ce utile?

La solution

Après avoir fait encore PLUS de recherches, je pense avoir la réponse à ma question.

Paul Stovell avait cette réponse légèrement modifiée à une question similaire sur le tableau de messages DDD . Remplacez & Quot; Client & Quot; pour " Employé " ;, et " Commande " pour " Violation " et vous avez l'idée.

  

Juste parce que le client fait référence à la commande   ne signifie pas nécessairement que l'ordre tombe   dans la racine agrégée du client.   Les adresses du client pourraient, mais   les ordres peuvent être indépendants (pour   Par exemple, vous pourriez avoir un service qui   traite toutes les nouvelles commandes, peu importe qui   le client est. Devoir partir   Client - & Gt; Les commandes n'ont aucun sens   ce scénario).

     

Du point de vue du domaine, vous pouvez   même remettre en question la validité de ceux   références (le client a référence à   une liste des commandes). Combien de fois allez-vous   réellement besoin de tous commandes pour un   client? Dans certains systèmes, il fait   sens, mais dans d'autres, un client   pourrait faire beaucoup de commandes. Les chances sont   vous voulez des commandes pour un client entre   une plage de dates ou des commandes pour un client   qui ne sont pas encore traités, ou les commandes   qui n'ont pas été payés, et ainsi de suite.   Le scénario dans lequel vous aurez besoin de tous   d'entre eux pourrait être relativement rare.   Cependant, il est beaucoup plus probable que   lorsque vous traitez avec un ordre, vous   veulent les informations client. Donc dans   code, Order.Customer.Name est utile,   mais Customer.Orders[0].LineItem.SKU -   probablement pas si utile. Bien sûr,   cela dépend totalement de votre entreprise   domaine.

En d'autres termes, la mise à jour du client n'a rien à voir avec la mise à jour des commandes. Et les ordres, ou violations, dans mon cas, pourraient être traités indépendamment des Clients / Employés.

Si les violations avaient des lignes de détail, les lignes Violation et Violation feraient alors partie du même agrégat, car la modification d'une ligne de violation affecterait probablement une violation.

EDIT ** Le problème ici dans mon domaine est que les violations n'ont aucun comportement. Ce sont essentiellement des enregistrements d'un événement survenu. Pas encore sûr des implications que cela a.

Autres conseils

Eric Evan déclare dans son livre La conception axée sur le domaine: s'attaquer à la complexité au cœur du logiciel ,

  

Un AGREGAT est un groupe d'objets associés que nous traitons comme une unité aux fins de la modification des données .

Il y a 2 points importants ici:

  1. Ces objets doivent être traités comme une & "unité &";
  2. .
  3. Aux fins de " modification des données ".

Je crois que dans votre scénario, Employé et Violation ne sont pas nécessairement une unité ensemble, alors que dans l'exemple de Order et OrderItem, ils font partie d'une seule unité.

Si vous modélisez les limites de l’agrégat, il est également important de savoir si vous avez des invariants dans votre agrégat. Les invariants sont des règles de gestion qui doivent être valides dans la & Quot; totalité & Quot; agrégat. Par exemple, comme dans l'exemple Order et OrderItem, vous pouvez avoir un invariant qui indique que le coût total de la commande doit être inférieur à un montant prédéfini. Dans ce cas, chaque fois que vous souhaitez ajouter un article de commande à la commande, cet invariant doit être appliqué pour garantir la validité de votre commande. Cependant, dans votre problème, je ne vois aucun invariant entre vos entités: employé et violation.

Réponse courte:

Je pense que Employee et Violation appartiennent chacun à 2 agrégats distincts. Chacune de ces entités ont également leurs propres racines globales. Donc, vous avez besoin de 2 référentiels: EmployeeRepository et ViolationRepository.

Je pense aussi que vous devriez avoir une association unidirectionnelle de Violation à Employé. De cette façon, chaque objet Violation sait à qui il appartient. Mais si vous souhaitez obtenir la liste de toutes les violations pour un employé en particulier, vous pouvez demander à ViolationRepository:

var list = repository.FindAllViolationsByEmployee(someEmployee);

Vous dites que vous avez des entités d'employé et des violations et que chaque violation n'a aucun comportement en soi. D'après ce que je peux lire ci-dessus, il me semble que vous pouvez avoir deux racines globales:

  • employé
  • EmployeeViolations (appelez-le EmployeeViolationCard ou EmployeeViolationRecords)

EmployeeViolations est identifié par le même ID d'employé et contient une collection d'objets de violation. Vous obtenez le comportement des employés et les violations séparées de cette façon et vous n'obtenez pas l'entité Violation sans comportement.

Si la violation est une entité ou un objet de valeur, vous devez décider en fonction de ses propriétés.

Je suis généralement d'accord avec Mosh sur ce point. Cependant, gardez à l'esprit la notion de transaction du point de vue commercial. Donc, je prends réellement & Quot; aux fins de la modification des données & Quot; signifier " aux fins de la transaction (s) " ;.

Les référentiels sont des vues du modèle de domaine. Dans un environnement de domaine, ces & Quot; vues & Quot; vraiment soutenir ou représenter une fonction ou une capacité de l'entreprise - une transaction. En l'occurrence, l'employé peut avoir une ou plusieurs violations et, le cas échéant, sont des aspects d'une transaction à un moment donné. Considérez vos cas d'utilisation.

Scénario: & "Un employé commet un acte qui constitue une violation du lieu de travail. &" C’est un type d’événement commercial (c’est-à-dire une transaction ou une partie d’une transaction plus importante, peut-être distribuée) qui s’est produit. L'objet de domaine affecté par la racine peut en réalité être vu sous plusieurs perspectives, ce qui explique sa confusion. Mais ce qu'il faut retenir, c'est le comportement d'une transaction commerciale, car vous souhaitez que vos processus métier modélisent le monde réel de la manière la plus précise possible. En termes de relations, comme dans une base de données relationnelle, votre modèle de domaine conceptuel devrait en fait l'indiquer déjà (c'est-à-dire l'associativité), qui peut souvent être lu dans les deux sens:

employé < ---- commet un ------- commis par ---- > Violation

Donc, pour ce cas d'utilisation, il serait juste de dire qu'il s'agit d'une transaction traitant de violations et que la racine - ou & "primaire &"; entité - est une violation. Ce serait alors votre racine globale à laquelle vous feriez référence pour cette activité ou ce processus d’affaires particulier. Mais cela ne veut pas dire que, pour une activité ou un processus différent, vous ne pouvez pas avoir une racine d'agrégat d'employé, telle que le & "Nouvel processus d'employé &". Si vous prenez des précautions, les références cycliques ne doivent pas avoir d'impact négatif, ni le fait de pouvoir parcourir votre modèle de domaine de plusieurs manières. Je vous préviendrai toutefois que la gestion de ce problème doit être envisagée et gérée par votre partie contrôleur de votre domaine métier, ou tout autre équivalent.

Hormis: en termes de modèles (c’est-à-dire MVC), le référentiel est une vue, les objets de domaine sont le modèle et il convient donc également d’employer une forme de modèle de contrôleur. Généralement, le contrôleur déclare l’implémentation concrète des référentiels (collections de racines agrégées) et l’accès à ceux-ci.

Dans le monde de l'accès aux données ...

En utilisant LINQ-To-SQL à titre d'exemple, le DataContext serait le contrôleur exposant une vue des entités Client et Commande. La vue est un type de table non déclaratif et orienté framework (équivalent approximatif de Repository). Notez que la vue conserve une référence à son contrôleur parent et passe souvent par le contrôleur pour contrôler quand et comment la vue se matérialise. Ainsi, le contrôleur est votre fournisseur, s’occupant de la cartographie, de la traduction, de l’hydratation des objets, etc. Le modèle est alors votre POCO de données. Quasiment un motif typique de MVC.

En utilisant N / Hibernate à titre d'exemple, ISession serait le contrôleur exposant une vue des entités Client et Commande par le biais de session.Enumerable (chaîne de caractères) ou session.Get (objet id) ou session.CreateCriteria (type of (Client)). Liste ()

Dans le monde de la logique métier ...

Customer { /*...*/ }

Employee { /*...*/ }

Repository<T> : IRepository<T>
              , IEnumerable<T>
              //, IQueryable<T>, IQueryProvider //optional

{ /**/ }

BusinessController {
 Repository<Customer>  Customers { get{ /*...*/ }} //aggregate root
 Repository<Order> Orders { get{ /*...*/ }} // aggregate root
}

En un mot, utilisez vos processus et transactions commerciaux comme guide, et laissez votre infrastructure métier évoluer naturellement au fur et à mesure que les processus / activités sont mis en œuvre ou restructurés. De plus, préférez la composabilité à la conception traditionnelle de la boîte noire. Lorsque vous arrivez au cloud computing orienté services, vous ne le regretterez pas. :)

Je me demandais quelle serait la conclusion?

Les "violations" deviennent une entité racine. Et les 'violations' seraient référencées par l'entité racine 'employé'. ie référentiel de violations < - > référentiel des employés

Mais vous êtes prêt à faire des violations une entité racine car il n’a aucun comportement.

Mais le "comportement" est-il un critère permettant de qualifier une entité racine? Je ne pense pas.

une question légèrement orthogonale pour tester la compréhension ici, en revenant à Order ... Exemple de OrderItem, il peut y avoir un module d'analyse dans le système qui souhaite consulter directement les OrderItems, c'est-à-dire obtenir tous les items de commande d'un produit particulier, ou tous les ordres. les éléments supérieurs à une valeur donnée, etc., avoir beaucoup de cas usuels comme ceux-là et conduire & "; racine agrégée &"; à l'extrême, pourrions-nous affirmer que OrderItem est une racine agrégée différente en soi ??

Cela dépend. Est-ce que tout changement / ajout / suppression d'une vioation modifie une partie de l'employé - par ex. stockez-vous le nombre de violations, ou le nombre de violations au cours des 3 dernières années contre un employé?

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top