2017-09-06 1 views
1

Étant donné un agrégat d'ordre, il se compose de Order et OrderItems. L'ordre est la racine agrégée. Le passage d'une commande est le seul scénario nécessitant une transaction pour la cohérence des données. Ou au moins il y a beaucoup de scénarios implique de changer les données à la fois dans l'ordre et orderItems qui n'exigent pas de transaction.Pourquoi chaque changement de données dans les agrégats devrait-il être en transaction?

Avant DDD, la transaction est une décision prise lors de la création de méthodes. Vous pensez généralement si cette méthode ou ce comportement doit être en transaction afin de maintenir la cohérence. DDD suggère de faire une transaction pour chaque comportement possible exposé par la racine agrégée. Cela peut effectivement conduire à plus d'interblocages.

Je pense que je n'ai pas besoin d'implémenter tous les changements de données dans la racine agrégée pour être en transaction.

Par exemple, si vous modifiez uniquement les détails d'expédition, pourquoi auriez-vous besoin d'une transaction? Si vous supprimez seulement un article de commande, pourquoi auriez-vous besoin d'une transaction? Donc pour les méthodes Order.UpdateOrder et Order.DeleteOrderItem, nous ne devrions pas considérer les transactions.

Quelque chose me manque?

Répondre

0

Oui, je pense que vous manquez quelque chose. Si vous concevez vos agrégats correctement, surtout si vous les faites suffisamment petits, vous n'aurez pas de transactions inutiles, du moins pas beaucoup. Vos agrégats doivent être hautement cohésifs, donc les propriétés/états qui sont modifiés simultanément doivent rester dans le même agrégat; c'est le point d'un agrégat, pour protéger l'accès concurrent à l'état.

Si vos agrégats sont plus grands qu'ils devraient être alors il y a un grand changement que les agrégats force-field sont trop larges et les commandes qui ne sont pas cohésives seront sérialisées pour rien. Sur le orders, il n'y aurait pas beaucoup de transactions échouées, car la probabilité d'ajouter un order item et de changer le order shipping details en même temps est très faible. Quoi qu'il en soit, les interblocages ne se produiront pas à cause des transactions dans tous les cas, mais des transactions échouées pourraient se produire.

+0

Pour les blocages possibles, vérifiez ce post. https://stackoverflow.com/questions/34662578/in-domain-driven-design-why-would-you-use-an-aggregate-object-and-what-key-pr – Costa

+0

Je dis que tous les comportements dans l'agrégat racine doivent être en transaction. Je pense que nous devrions considérer la transaction quand un problème de cohérence est possible, et cela devrait être basé sur l'analyse du comportement. Par exemple, si vous modifiez uniquement les détails d'expédition, pourquoi vous auriez besoin d'une transaction. Si vous supprimez uniquement un article de commande, pourquoi aurait-il besoin d'une transaction? Donc, dans les méthodes Order.UpdateOrder, et Order.DeleteOrderItem, nous ne devrions pas considérer les transactions. – Costa

+0

@Costa Mais vous avez besoin de transactions dans ces cas, sinon cela pourrait être compliqué en fonction de l'implémentation de votre dépôt. Gardez à l'esprit que l'agrégat est entièrement chargé quand/avant de traiter une commande, il ne devrait pas y avoir de chargement paresseux. –

0

Dans la forme la plus pure votre dépôt aurait très peu de méthodes:

public interface IAggregateRepository 
{ 
    AggregateRoot Get(Guid id); 
    void Save(AggregateRoot instance); 
} 

Il n'y a pas de distinction entre les cas d'utilisation/commandes dans ce scénario. Vous ne savez pas nécessairement si une transaction est requise ou non.

Une autre considération est que les transactions doivent être traitées dans l'intégration/application couche. Cela déplace la gestion des transactions encore plus loin des interactions de domaine.

Vous pouvez demander à l'application de prendre connaissance des cas d'utilisation spécifiques et de décider de renoncer à des transactions pour certaines commandes. Cependant, cela peut être plus d'efforts que cela vaut la peine.

Un dernier point est qu'une transaction n'est pas toujours seulement ce que vous faites, mais aussi sur ce que autres font.

Je voudrais faire preuve de prudence et utiliser plutôt une transaction.S'il y a une raison spécifique de ne pas utiliser une transaction, c'est certainement une option mais cela semble plus approprié pour les lectures.

0

Si vous avez besoin quelque part dans le système de mise à jour seulement les détails d'expédition, que de suivre l'approche DDD de base, vous pouvez avoir un autre contexte borné global différent, nous allons l'appeler ShippingRequest, qui a seulement deux champs, OrderId et ShippingDetails , et qui éventuellement peuvent ou non correspondre à la même table sous-jacente. Ensuite, cet agrégat est implicitement couvert par la transaction car il correspond à une seule table. Ou peut-être que vous ne voulez pas vous soucier de tous ces contextes bornés, des langages et des agrégats omniprésents, car DDD ne vaut pas la peine d'être implémenté et une approche CRUD/script de transaction traditionnelle est suffisante.

Le problème est également que DDD est souvent expliqué sur de mauvais exemples comme celui-ci. Agrégat définit une limite de cohérence, un invariant qui représente votre règle métier. Ainsi, dans le cas d'une commande en tant que granulat, disons que l'ordre reçoit un total maximum autorisé, qui ne doit pas être dépassé. Cela devient un agrégat naturel, car chaque fois que vous voulez ajouter ou supprimer un élément, l'agrégat entier doit être récupéré et mis à jour en tant qu'unité atomique unique.

+0

Même sans total maximum, OrderItem ne peut pas vivre dans le modèle sans Order, donc il ne peut pas être root, il doit être une partie de l'ordre agrégé. – Costa

+0

Bien sûr, il peut être, s'il a la propriété OrderId, que vous devez affecter du constructeur ... –

+0

L'attribut OrderID ne peut pas être ajouté à OrderItem car il est contre l'encapsulation OO. – Costa