2017-02-08 62 views
2

我一直在尋找不同的CQRS samples,其中大多數人使用的命令處理程序不保存UnitOfWork(即在Entity Framework的情況下爲DataContext)。類似這樣的:爲什麼CQRS命令處理程序排除保存UnitOfWork?

public void Handle(Command message) 
    { 
     var course = Mapper.Map<Command, Course>(message); 

     _db.Courses.Add(course); 
    } 

保存(和事務提交)通常發生在後臺處理請求時。

我見過很多CQRS領導者的這種方法,但我從來沒有聽說過它的推理。

這種方法的最大問題是,當你需要在處理程序調用返回後(這種情況發生很多)時需要獲得實體Id的情況。有很明顯的方法可以解決它(即使用Guid,預先從數據庫中請求唯一標識等),但看起來很笨拙。

但是這種方法的優點是什麼?從理論上講,如果每個請求有幾個處理程序,它可以幫助不進行多次數據庫往返。但它並沒有發生很多。我想到的另一個優點是,我們不必鍵入該例程保存呼叫並讓它自動發生。這有點不錯,但它是否超重Id代的問題?

回答

1

爲什麼CQRS命令處理程序排除保存UnitOfWork?

我認爲埃文斯,Domain Driven Design,第6章域對象的生命週期開始。

還有就是用於處理的數據庫訪問技術挑戰技術筏....

但即便如此,記下所已丟失。我們不再考慮領域模型中的概念。我們的代碼不會傳達關於業務的信息,它會操縱數據檢索技術。

的想法是,在代碼中的這一點上,我們與域模型工作,而不是着眼於數據模型

存儲庫升降機從客戶端,現在可以跟一個簡單的釋意接口,並要求它在模型

埃文斯而言需要一個巨大的負擔是非常有力的關於此,在交易的情況下

將交易控制權交給客戶端。雖然REPOSITORY會插入和刪除數據庫,但它通常不會提交任何內容。舉例來說,在保存後很容易提交,但客戶端可能具有正確啓動和提交工作單元的上下文。如果REPOSITORY不動手,交易管理將變得更簡單。

一些其他注意事項:

這種方法的最大問題是情況下,當你需要的是返回的句柄調用後得到一個實體ID的權利(發生了不少)。

這通常表明您正在對抗錯誤的問題。參見Marc de Graauw,Nobody Needs Reliable Messaging

+0

我覺得這一切都使存儲庫更有意義。當我們直接使用DataContext時,我們不使用域,我們修改數據存儲。然後我們不做最後一步(保存我們修改的內容)並假裝解除域對象操作並使用數據存儲。 – SiberianGuy

1

命令處理程序的一個重要功能是它不返回任何內容(除了例外)。這是一個微妙的點,但如果你知道所有的命令處理程序不返回任何東西,那麼你可以節省大量的代碼,並簡化或構建更強大的代碼庫。

但是,如果你沒有返回任何東西,那麼你有這種情況,你需要在進程開始時的id。我認爲使用GUID是一個很好的解決方案。

從數據庫中預取唯一標識符的問題充滿了問題,如果可能的話,我會避免使用這種方法。

這裏有一些優勢:

  1. 所有的命令處理程序都會有一個共同的接口
  2. 因此你可以寫它支持所有的命令處理程序助手代碼。例如命令路由器,安全性和權限檢查,日誌記錄,性能監視,消息隊列...
  3. 它可以顯着減少您需要編寫的代碼量
  4. 它可以顯着降低您需要編寫代碼的複雜性
  5. 測試是更容易和更強大的

這些都只是幾關我的頭頂。

爲什麼不包括一個工作單元?

你可能是簡短的答案。但我喜歡將持久性責任移出處理程序。處理程序可能會調用它,但實際的持久性是在別處完成的(我的偏好在大多數情況下是在事件存儲中)。

+0

感謝您的回答,但我不會去調用Guids優雅:) – SiberianGuy

+0

爲什麼不呢?創建一個獨立於數據庫的全局唯一ID。我認爲這很酷。 – Codescribler

+0

呃...他們很難看:)如果你需要在url中顯示基於guid的id,它永遠不會感覺正確 – SiberianGuy