6

CONTEXTE: J'ai un objet domaine Person. C'est une racine agrégée. J'ai inclus une partie de la classe ci-dessous. J'expose des méthodes pour effectuer les comportements d'objets. Par exemple, pour ajouter un BankAccount, j'ai la méthode AddBankAccount(). Je n'ai pas inclus toutes les méthodes de la classe, mais il suffit de dire que toute propriété publique doit être mise à jour en utilisant une méthode.Domain Driven Design - Comment gérer les mises à jour pour certaines parties de vos racines agrégées

Je vais créer un référentiel IPerson pour gérer les opérations CRUD.

public interface IPersonRepository 
{ 
    void Save(Person p); 
    //...other methods 
} 

QUESTION: Comment puis-je dire le dépôt quels champs doivent être mis à jour lorsque nous mettons à jour une personne existante? Par exemple, si j'ajoute un compte bancaire à une personne existante, comment puis-je communiquer cette information au référentiel lorsque repository.Save() est appelée?

Dans le référentiel, il est facile de déterminer quand une nouvelle personne est créée, mais lorsqu'une personne existante existe et que vous mettez à jour des champs sur cette personne, je ne sais pas comment la communiquer au référentiel.

Je ne veux pas polluer mon objet Person avec des informations sur les champs qui sont mis à jour.

Je pourrais avoir des méthodes séparées sur le dépôt comme .UpdateEmail(), AddBankAccount() mais cela semble être trop. Je voudrais une méthode simple .Save() sur le référentiel et il détermine ce qui doit être mis à jour d'une manière ou d'une autre.

Comment les autres ont-ils géré cette situation?

J'ai fait des recherches sur le web et stackoverflow mais je n'ai rien trouvé. Je ne dois pas chercher correctement parce que cela semble quelque chose de simple quand il s'agit de la persistance dans le paradigme DDD. Je pourrais aussi être loin de ma compréhension de DDD :-)

public class Person : DomainObject 
{ 
    public Person(int Id, string FirstName, string LastName, 
     string Name, string Email) 
    { 
     this.Id = Id; 
     this.CreditCards = new List<CreditCard>(); 
     this.BankAccounts = new List<BankAccount>(); 
     this.PhoneNumbers = new List<PhoneNumber>(); 
     this.Sponsorships = new List<Sponsorship>(); 
    } 

    public string FirstName { get; private set; } 
    public string LastName { get; private set; } 
    public string Name{ get; private set; } 
    public string Email { get; private set; } 
    public string LoginName { get; private set; } 

    public ICollection<CreditCard> CreditCards { get; private set; } 

    public ICollection<BankAccount> BankAccounts { get; private set; } 

    public ICollection<PhoneNumber> PhoneNumbers { get; private set; } 

    public void AddBankAccount(BankAccount accountToAdd, IBankAccountValidator bankAccountValidator) 
    { 
     bankAccountValidator.Validate(accountToAdd); 

     this.BankAccounts.Add(accountToAdd); 
    } 

    public void AddCreditCard(CreditCard creditCardToAdd, ICreditCardValidator ccValidator) 
    { 
     ccValidator.Validate(creditCardToAdd); 

     this.CreditCards.Add(creditCardToAdd); 
    } 

    public void UpdateEmail(string NewEmail) 
    { 
     this.Email = NewEmail; 
    } 
+0

Bonjour, je vois que personne n'a vraiment répondu à votre question. Eh bien, au moins, je ne pense pas que dire "utiliser un ORM" est une solution. Qu'avez-vous fini par faire? –

Répondre

2

Il est un exemple de l'interface de dépôt S#arp Architecture projet. Il est similaire à PoEAA Data Mapper car il a également été utilisé pour les opérations CRUD.

public interface IRepositoryWithTypedId<T, IdT> 
{ 
    T Get(IdT id);  
    IList<T> GetAll();  
    IList<T> FindAll(IDictionary<string, object> propertyValuePairs);  
    T FindOne(IDictionary<string, object> propertyValuePairs);  
    T SaveOrUpdate(T entity);  
    void Delete(T entity);  
    IDbContext DbContext { get; } 
} 

Comme vous pouvez le voir, il n'existe aucune méthode de mise à jour pour les propriétés spécifiques d'une entité. L'entité entière est fournie en tant qu'argument dans la méthode SaveOrUpdate.

Lorsque les propriétés de votre entité de domaine sont vous mis à jour devez dire à votre Unit of Work cette entité est « sale » et doit être enregistré dans le stockage (par exemple, base de données)

PoEAA Unit of Work

Vous ne devriez pas polluer votre objet Personne avec des informations sur les champs mis à jour, mais il est nécessaire de suivre les informations si l'entité est mise à jour.

Il peut y avoir des méthodes de la classe DomainObject qui indiquent 'Unité de Travail' si l'entité est 'nouvelle', 'sale' ou 'supprimée'. Et puis votre UoW lui-même pourrait invoquer des méthodes de dépôt appropriées - 'SaveOrUpdate' ou 'Delete'.

En dépit du fait que les Frameworks ORM modernes comme NHibernate ou EntityFramework ont leurs propres implémentations de 'Unit of Work', les gens ont tendance à écrire leurs propres wrappers/abstractions pour eux.

+0

Merci pour vos commentaires, très appréciés !. Malheureusement, je ne sais toujours pas comment mon objet personne peut faire savoir au référentiel qu'une carte de crédit a été ajoutée et doit être sauvegardée ou que l'e-mail a été mis à jour et il a seulement besoin d'être mis à jour. Mon objet Person contient de nombreux autres objets mais, en réalité, ils sont mappés à plusieurs tables de données. – RDotLee

+1

Utilisez-vous un ORM? Qu'est-ce que vous utilisez pour interagir avec DB dans vos référentiels? ** 0 ** ** ** ** Si CreditCard est un enfant de la racine agrégée et n'a pas de sens sans personne de CreditCards (table CreditCards en DB) avec PersonRepository. ** 2nd ** -> Si CreditCard est une entité logique sans Person, vous devez créer/mettre à jour CreditCard avec son propre CreditCardRepository, puis créer/mettre à jour la personne avec PersonRepository. –

+0

Merci encore pour vos commentaires. Dans votre 1er scénario, j'ai de la difficulté à comprendre comment la PersonRepsitory sait qu'une carte de crédit a été ajoutée et doit être insérée. Ou comment une carte de crédit a été modifiée et doit être mise à jour. – RDotLee

0

Ce que je fais pour résoudre ce problème, est l'ajout d'une interface à mes objets de domaine:

interface IDirtyTracker { 
    bool IsDirty {get;} 
    void MarkClean(); 
    void MarkDirty(); 
} 

La classe de base DomainObject pourrait mettre en œuvre IDirtyTracker, puis des dépôts etc. pourrait utiliser IsDirty pour vérifier si elle est sale ou propre.

Dans chaque setter qui fait un changement:

void SetValue() { 
    this._value = newValue; 
    this.MarkDirty(); 
} 

Cela ne vous donne pas le contrôle du grain fin, mais il est un moyen simple d'éviter des mises à jour inutiles au niveau du référentiel. Pour faciliter cela, une méthode GetPropertiesToIncludeInDirtyCheck pourrait être ajoutée, ce qui permettrait de récupérer une liste de propriétés qui doivent être vérifiées.

interface IDirtyTracker { 
    IENumerable<Object> GetPropertiesToIncludeInDirtyCheck(); 
} 
Questions connexes