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

标签 domain-driven-design repository-pattern ddd-repositories aggregateroot

背景:我有一个 Person 域对象。它是一个聚合根。我已经包括了下面类(class)的一部分。

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

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

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

问题 :当我们更新现有人员时,我如何告诉存储库哪些字段需要更新?例如,如果我向现有人员添加银行帐户,我如何在调用 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;
    }

最佳答案

S#arp Architecture 中有一个 Repository 接口(interface)示例项目。类似于 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; }
}

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

当您的域实体的属性被更新时,您应该告诉您的 Unit of Work该实体是“脏”的,应该保存到存储中(例如数据库)

PoEAA Unit of Work

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

可能有类 DomainObject 的方法如果实体是"new"、“脏”或“已删除”,它会告诉“工作单元”。然后您的 UoW 本身可能会调用适当的存储库方法 - “SaveOrUpdate”或“Delete”。

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

关于domain-driven-design - 领域驱动设计 - 如何处理部分聚合根的更新,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19407390/

相关文章:

domain-driven-design - 行为驱动开发 (BDD) 如何与领域驱动设计 (DDD) 协同工作

c# - EF Code First 实体对象不能被 IEntityChangeTracker 的多个实例引用

domain-driven-design - DDD : Aggregate design - Referencing between aggregates

java - DDD - 存储库和多对多关系

domain-driven-design - 如何在 ddd 中实现聚合之间的引用?

design-patterns - 事件溯源中的聚合到底是什么?

c# - 没有服务定位器的领域事件

php - 域模型 MVC 中的 native 数据库查询

c# - DataContext 的生命周期,LinqToSql

domain-driven-design - DDD : one aggregate root , 多个持久数据源