域驱动设计 - 如何处理聚合根部分的更新

RDo*_*Lee 6 domain-driven-design ddd-repositories aggregateroot repository-pattern

背景: 我有一个Person域对象.它是一个聚合根.我已经在下面列出了一部分课程.

我正在公开执行对象行为的方法.例如,要添加BankAccount,我有AddBankAccount()方法.我没有包括该类的所有方法,但足以说必须使用方法更新任何公共属性.

我将创建一个IPerson存储库来处理CRUD操作.

public interface IPersonRepository
{ 
    void Save(Person p);
    //...other methods
}
Run Code Online (Sandbox Code Playgroud)

问题:在更新现有人员时,如何告知存储库需要更新哪些字段?例如,如果我向现有人员添加银行帐户,当调用repository.Save()时,如何将此信息传递给存储库?

在存储库中,很容易确定何时创建新人,但是当存在现有人员并且您更新该人员的字段时,我不确定如何将其传达给存储库.

我不想用有关哪些字段更新的信息污染我的Person对象.

我可以在存储库上有单独的方法,如.UpdateEmail(),AddBankAccount(),但这感觉有点矫枉过正.我想在存储库上使用一个简单的.Save()方法,它确定需要以某种方式更新的内容.

别人怎么处理这种情况?

我搜索了网络和stackoverflow但没有找到任何东西.我一定不能正确搜索,因为在DDD范例中持久化时,这似乎很简单.我也可以对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;
    }
Run Code Online (Sandbox Code Playgroud)

Ily*_*kin 3

S#arp Architecture项目中有一个存储库接口的示例。它与PoEAA Data Mapper类似,因为它也用于 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; }
}
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,实体的特定属性没有更新方法。整个实体作为参数提供给方法SaveOrUpdate

当域实体的属性正在更新时,您应该告诉您的工作单元该实体是“脏的”并且应该保存到存储中(例如数据库)

PoEAA 工作单元

您不应使用有关更新字段的信息污染 Person 对象,但如果实体更新,则需要跟踪信息。

该类可能有一些方法DomainObject告诉“工作单元”实体是“新的”、“脏的”还是“已删除的”。然后您的 UoW 本身可能会调用适当的存储库方法 -“SaveOrUpdate”或“Delete”。

尽管现代 ORM 框架(如NHibernateEntityFramework)有自己的“工作单元”实现,但人们倾向于为它们编写自己的包装器/抽象。