6

背景:我有一個Person域對象。它是一個聚合根。我已經在下面列出了一部分課程。域驅動設計 - 如何處理聚合根部分的更新

我正在公開執行對象行爲的方法。例如,要添加一個BankAccount,我有AddBankAccount()方法。我沒有包括班級的所有方法,但足以說任何公共財產必須使用方法進行更新。

我將創建一個IPerson存儲庫來處理CRUD操作。

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

問題:我怎麼知道哪些字段需要更新的時候,我們要更新現有的人的資料庫?例如,如果我向現有人員添加銀行帳戶,那麼在調用repository.Save()時如何將此信息傳遞到存儲庫?

在存儲庫中,很容易確定何時創建新人員,但是當現有人員存在並且您更新該人員的字段時,我不確定如何與存儲庫通信。

我不想污染我的Person對象,關於更新哪些字段的信息。

我可以有像.UpdateEmail(),AddBankAccount()這樣的存儲庫上的單獨方法,但感覺像是矯枉過正。我想在存儲庫上使用一個簡單的.Save()方法,並以某種方式確定需要更新的內容。

其他人怎麼處理這種情況?

我已經搜索了網絡和計算器,但還沒有找到任何東西。我不能正確搜索,因爲在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; 
    } 
+0

嗨,我看到沒有人真正回答你的問題。那麼,至少我不認爲說「使用ORM」是一個解決方案。你最終做了什麼? –

回答

2

有來自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; } 
} 

正如你所看到的,沒有實體特定屬性的更新方法。整個實體作爲參數提供給方法SaveOrUpdate

當你的域實體的屬性正在更新你應該告訴你Unit of Work該實體是「髒」,並應保存到存儲器(例如數據庫)

PoEAA Unit of Work

你不應該污染你的Person對象提供有關更新字段的信息,但如果更新實體,則需要跟蹤信息。

如果entity是'new','dirty'或'deleted',那麼可能有DomainObject類的方法告訴'工作單元'。然後你的UoW本身可能會調用正確的存儲庫方法 - 'SaveOrUpdate'或'Delete'。

儘管現代ORM框架如NHibernateEntityFramework有自己的'工作單元'實現,但人們傾向於爲他們編寫自己的包裝/抽象。

+0

感謝您的意見,非常感謝! 不幸的是,我仍然不知道我的個人對象如何使存儲庫知道信用卡已被添加並需要保存,或者電子郵件已被更新,並且只需要更新。我的Person對象包含許多其他對象,但實際上它們映射到多個數據表。 – RDotLee

+1

你使用任何ORM?你在儲存庫中用什麼與數據庫交互? 一般有兩種選擇: ** 1st ** - >如果CreditCard是聚合根的孩子,沒有Person就沒有意義,那麼您應該更新/創建Person(人員表中的數據庫),然後更新集合PersonRepository中的CreditCards(DB中的CreditCards表)。 ** 2nd ** - >如果CreditCard是一個沒有Person的實體,那麼您應該使用自己的CreditCardRepository創建/更新CreditCard,然後使用PersonRepository創建/更新Person。 –

+0

再次感謝您的意見。在你的第一個場景中,我難以理解的是PersonRepsitory如何知道信用卡已被添加並需要插入。或者如何修改信用卡並需要更新。 – RDotLee

0

我在做什麼來解決這個問題,是增加一個接口到我的域對象:

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

基礎DomainObject類可以實現IDirtyTracker,然後倉庫等可以使用IsDirty來檢查它是否髒或乾淨。

在此進行了更改每個二傳手:

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

這不會給你細粒度的檢查,但它是一個簡單的方法,以避免在庫級別一些不必要的更新。

爲了更容易一點,可以添加一個GetPropertiesToIncludeInDirtyCheck方法,它將檢索需要檢查的屬性列表。

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