Question

BACKGROUND: I have a Person domain object. It is an aggregate root. I have included a portion of the class below.

I am exposing methods to perform the objects behaviors. For instance, to add a BankAccount I have the AddBankAccount() method. I have not included all the methods of the class but suffice to say that any public property must be updated using a method.

I am going to create an IPerson repository to handle the CRUD operations.

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

QUESTION: How do I tell the repository which fields need to be updated when we are updating an existing person? For example, If I add a bank account to an existing person how do I communicate this information to the repository when repository.Save() is called?

In the repository it is easy to determine when a new person is created, but when an existing person exists and you update fields on that person, i'm not sure how to communicate this to the repository.

I don't want to pollute my Person object with information about which fields are updated.

I could have separate methods on the repository like .UpdateEmail(), AddBankAccount() but that feels like overkill. I would like a simple .Save() method on the repository and it determines what needs to update in some manner.

How have others handled this situation?

I have searched the web and stackoverflow but haven't found anything. I must not be searching correctly because this seems like something simple when it comes to persistence within the DDD paradigm. I could also be way off on my understanding of 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;
    }
Was it helpful?

Solution

There is an example of Repository interface from S#arp Architecture project. It is similar to PoEAA Data Mapper because it used to CRUD operations also.

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; }
}

As you can see, there is no update method for specific properties of an entity. The whole entity is provided as an argument into the method SaveOrUpdate.

When properties of your domain entity are being updated you should tell your Unit of Work that entity is 'dirty' and should be saved into storage (e.g. database)

PoEAA Unit of Work

You should not pollute your Person object with information about updated fields but it is needed to track information if entity is updated.

There might be methods of the class DomainObject which tell 'Unit of Work' if entity is 'new', 'dirty' or 'deleted'. And then your UoW itself might invoke proper repository methods - 'SaveOrUpdate' or 'Delete'.

Despite the fact that modern ORM Frameworks like NHibernate or EntityFramework have their own implementations of 'Unit of Work', people tend to write their own wrappers/ abstractions for them.

OTHER TIPS

What I'm doing to solve this problem, is adding an interface to my domain objects:

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

The base DomainObject class could implement IDirtyTracker, and then repositories etc. could use IsDirty to check if it's dirty or clean.

In each setter that makes a change:

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

This does not give you fine grain checking, but it's a simple way to avoid some unnecessary updates at the repository level.

To make this a little easier, a GetPropertiesToIncludeInDirtyCheck method could be added, which would retrieve a list of properties which need to be checked.

interface IDirtyTracker {
    IENumerable<Object> GetPropertiesToIncludeInDirtyCheck();
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top