2011-12-11 60 views
0

更新實體時,我需要級聯許多更改。我可以像下面那樣做,但這是醜陋的imho(太多的參數已經和計數)。存儲庫模式和許多級聯更改

public class PageRepository : IPageRepository 
{ 
    public void Update(Page page, string oldPath, PageState oldState, IEnumerable<Tag> oldTags /* Maybe even more stuff */) 
    { 
     using(var t = session.BeginTransaction()) 
     { 
      if(/* path has changed */) 
      { 
       // move descendant pages 
      } 
      if(/* state has changed to public */) 
      { 
       // publish hidden descendant pages 
      } 
      if(/* state has changed to non-public */) 
      { 
       // hide public descendant pages 
      } 
      if(page is ITaggable) 
      { 
       foreach(var tag in ((ITaggable)page).Tags.Except(oldTags)) 
       { 
        // increase tag count in ancestor pages 
       } 
       foreach(var tag in oldTags.Except(((ITaggable)page).Tags)) 
       { 
        // decrease tag count in ancestor pages 
       } 
      } 

      // ... 

      session.Update(page); 
      t.Commit(); 
     } 
    } 
} 

有什麼模式可以幫助使清潔劑?

我已經想過分裂,要多種方法

pageRepo.BeginTransaction(); 
pageRepo.Update(page); 
if(/* path has changed */) 
{ 
    pageRepo.MoveDescendants(page, oldPath); 
} 
// ... 

pageRepo.Commit(); 

,但我不喜歡手動事務處理。我得到的另一個想法是

using(var batch = pageRepo.CreateUpdateBatch(page)) 
{ 
    if(/* path has changed */) 
    { 
     batch.MoveDescendants(oldPath); 
    } 
    // ... 
    batch.Commit(); 
} 

回答

1

這不屬於一個存儲庫。級聯更改應該由某種協調所有更改的工廠或服務類來管理。

保持您的存儲庫只關心檢索和保存數據,而不是保持數據完整性。這些是應該在域代碼中執行的業務規則,而不是存儲庫實現。

+0

如果最後一步失敗怎麼辦?如果前面的步驟事務沒有了,我怎樣才能回滾更改? –

+1

不要將代碼中的using代碼塊封裝在存儲庫中。相反,在會話周圍包裝IUnitOfWork接口,僅公開BeginTransation()和Commit()方法,然後從存儲庫中公開該接口。這樣,您可以從協調類調用UnitOfWork.BeginTransaction()和UnitOfWork.Commit()方法,而不是從存儲庫中調用。 – danludwig