2017-05-24 1 views
0

J'ai ce modèle de domaine simple. L'utilisateur effectue une activité qui a durée et distance. Pour chaque activité, un ou plusieurs engins peuvent être affectés (chaussures pour courir). Après l'affectation, la durée et la distance sont ajoutées aux totaux sur l'engrenage.Modification de deux agrégats dans une seule transaction (DDD)

Les deux Activity et GearItem sont des racines agrégées. Lorsque j'attribue un élément à une activité, je dois ajouter l'identifiant de l'élément à l'activité et mettre à jour les totaux sur l'élément.

Comment orchestrer cette opération?

  1. Appel GearItem.AssignUsage() directement à partir Activity.AddItem()?
  2. Faites-le dans un service d'application en une seule transaction, en appelant GearItem.AssignUsage() juste après Activity.AddItem() (cela casse la règle d'une transaction par AR).
  3. Utiliser l'événement de domaine (classe statique de Udi Dahan) - mais comment et où éviter un problème de transaction unique?
  4. Ou autre chose, beaucoup mieux?

GearItem AR, contient les totaux d'activités:

public class GearItem: Entity<GearItem> 
{ 
    ... 
public Usage AssignedUsage { get; private set; }; 

    public void AssignUsage(Activity activity) 
    { 
    AssignedUsage = new Usage(AssignedUsage.Time + activity.Time, 
    AssignedUsage.Distance + activity.Distance, AssignedUsage.Uses + 1); 
    }  
} 

activité AR, contient les ID de GearItems assignés:

public class Activity: Entity<Activity> 
{ 
    ... 
    private List<int> items = new List<int>(); 
    public TimeSpan Time { get; } 
    public double Distance { get; } 

    public bool AddItem(GearItem item) 
    { 
    if (items.Contains(item.Id)) return false; 

    items.Add(item.Id); 
    return true; 
    } 
} 

objet de valeur d'utilisation:

public class Usage: ValueObject<Usage> 
{ 
    ... 
    public TimeSpan Time { get; private set; } 
    public double Distance { get; private set; } 
    public int Uses { get; private set; } 
} 

Répondre

2

Vous devriez résister à la tentation de modifier deux agrégats en une seule transaction. Il y a deux règles qui vous aident à ne pas faire:

  1. Référence Autres agrégats seulement par leur ID
  2. Utilisation Cohérence Eventual en dehors des limites

Ainsi, afin de mettre à jour le AssignedUsage pour une GearItem vous utiliserez la cohérence éventuelle.

Vous pouvez le faire en utilisant des événements de domaine ou en calculant périodiquement les utilisations pour tous GearItems.

Utilisation des événements de domaine:

Après un GearItem est affecté à une activité, vous publiez un événement GearItemAssignedToActivity qui est pris par un Process manager qui appelle GearItem.AssignUsage(Time,Distance) dans une nouvelle transaction (en premier chargement du GearItem en utilisant son ID du dépôt).

mise à jour périodiquement l'utilisation de GearItem

Dans une tâche cron/programmée/tout ce que vous réinitialiser l'utilisation à chaque GearItem, puis charger tous les Activity et la charge et appeler GearItem.AssignUsage(Time,Distance) pour chaque attribué GearItem.

Aussi, je suggère que vous découpler les deux agrégats et ne pas passer des références aux appels de méthode. Par exemple, vous ne devez pas passer tout l'agrégat d'activité à la méthode GearItem.AssignUsage, mais uniquement les propriétés requises. De cette façon, un GearItem ne doit pas connaître ou dépendre de Activity entier.