一個儲存層轉接器的職責
獲取輸入-> 將輸入轉換成對應資料庫格式 -> 將輸入資料傳遞給資料庫 -> 把資料庫的輸出轉換成應用程式 -> 回傳輸出資料。
最常見的就是 傳入 ORM, ORM 轉換成 資料庫格式 -> 傳遞給資料庫儲存後回傳 -> 當 DB 結果轉換成 ORM,傳回該 ORM
而其中最需要釐清的觀念是,傳遞給儲存層轉接器 的 輸入模型(Input Model) 和 輸出模型(Output Model) 是 歸屬在應用程式層的,而非儲存層轉接器,原因是我們應該實際去思考 Domain 領域內的模型才是最重要的,儲存層應該要配合其異動而做修改,而不是當 DB 結構異動時去調整 Domain 領域內的模型。
而對於分割 應用程式核心 可用的資料庫作業的轉接埠介面
可以分成 單一集中式的輸出轉接埠
和 透過介面隔離原則 (ISP) ,將單一過廣的介面拆分為多個,且用戶端只使用最低限度所需的方法。
不過實際上還是得看你的需求,有得時候你就想表達一組內聚力強、高度關係的資料庫作業。
接續上面,接著要來看的是 儲存層轉接器
以 DDD 為例,會更推薦我們 以 “聚合” 為單位,來切割出不同的儲存層轉接器,這樣使得程式碼更加清晰易懂。
而不同的 Bounded Context 會有各自的儲存需求,就需要各自的建立儲存轉接器(一個或多個)。而不同 Bounded Context 之間是不能直接存取的,是必須透過 對方的輸入轉接埠 獲取才行。
那我們到底該不該直接把領域內的實體,直接存入資料庫呢?
答案是 不行。 建議還是需要先轉換一層轉換(DTO),原因是直接將領域模型傳給了儲存轉接器,那就代表把細節也暴露出去了,導致資料庫的資料對於 領域模型有深深的耦合關係;換句話說,當我資料庫讀取的資料,如果沒有夠過轉換層的轉換關係,是不是就代表 領域模型 是 對於資料庫是直接的耦合
那 database transaction 到底該歸在哪呢?
答案是 應用服務。原因是 對於儲存層轉接器來說,根本不會知道 它和哪些作業是在同一個使用案例底下的,意思是說儲存層就只有負責儲存 根本看不出 Context,自然而然也就不知道該 Rollback 哪些東西 該 Commit 哪些東西。