目前我正在學習 DDD 和 CQRS 方法。我開始了一個與餐廳領域相關的專案。
我發現(使用事件風暴)的模塊之一是選單。在選單模塊中,餐廳經理可以存盤多個選單。Menu 是 AggregateRoot,它在選單中的組和連接項(位置)之間強制執行規則。
有問題的規則:
- 餐廳中的一個選單可以同時激活。
- 選單的內部名稱在餐廳內必須是唯一的。
為了執行該規則,我嘗試將 Restaurant 存盤庫介面傳遞給 Menu(我更關注 1. 規則,因為 2. 更難)。我覺得我做錯了什么。我有一個使用域服務來強制執行的想法,經過分析,我認為它不會更好。你對我有什么建議嗎?謝謝 :)
public class Menu : AggregateRoot<MenuId>
{
public string InternalName { get; private set; }
public RestaurantId RestaurantId { get; private set; }
public IReadOnlyList<Group> Groups => _groups;
private List<Group> _groups = new();
...
internal void Activate()
{
CheckRule(new ActiveMenuMustHaveAtLeastOneGroup(_groups));
_groups.ForEach(x => x.CheckConsistency());
}
public void ChangeInternalName(string newInternalName, IRestaurantRepository
restaurantRepository)
{
CheckRule(new InternalNameMustBeUniqueInRestaurantMenusRule(RestaurantId,
newInternalName, restaurantRepository));
InternalName = newInternalName;
}
}
public class Restaurant : AggregateRoot<RestaurantId>
{
public MenuId ActiveMenuId { get; private set; }
public IReadOnlyList<MenuId> MenuIds => _menuIds;
private List<MenuId> _menuIds = new();
...
public void ChangeActiveMenu(MenuId newActiveMenuId, IMenuRepository menuRepository)
{
CheckMenuExists(newActiveMenuId);
CheckRule(new CannotActivateActiveMenuRule(ActiveMenuId, newActiveMenuId));
var menu = menuRepository.GetAsync(newActiveMenuId).Result;
menu.Activate();
ActiveMenuId = newActiveMenuId;
}
...
}
uj5u.com熱心網友回復:
好的,讓我們嘗試從頂部處理它 - 請注意,我的答案是> 基于意見<,就像大多數設計決策一樣。
對于第一個問題:
它的Restaurant的作業分配活動的選單,所以這個總量應持有虱子耦合到Menu-假設它存盤的ID。只有一個身份證件。
選擇新選單激活時,RestaurantAR 可以輕松檢查它是否是當前 id,無需存盤庫。
現在,如果給定的選單 id 不同,那么Restaurant應該有一種方法來通知Menu有關更改的背景關系-這是一件好事嗎,該選單知道其是否處于活動狀態-那完全是另一回事。
所以,這里有帶有事件處理程式的 CQRS -Restaurant應該發出一個MenuChanged事件,并且這個事件處理程式應該負責更新menu聚合。
因此,您應該在您的ChangeActiveMenu方法中啟動域事件,當聚合被持久化時(通常由存盤庫執行持久化),它將被啟動。
public void ChangeActiveMenu(MenuId newActiveMenuId)
{
CheckRule(new CannotActivateActiveMenuRule(ActiveMenuId, newActiveMenuId));
ActiveMenuId = newActiveMenuId;
this.EventStore.Add(new MenuChangedEvent(newActiveMenuId));
}
現在激活選單的作業交給MenuChangedEvent處理程式 - 通常使用流行的 MediatR 庫來完成。
第二個問題:可以通過多種方式檢查名稱在聚合根中的唯一性。
有一件事是肯定的 - 聚合不應該強制不變數超出它的范圍。因此,在這種情況下,不變數是一個Name,跨越邊界是讓Menu檢查多個聚合實體的一致性。
一方面,您可以實作一個域服務,該服務將獲取存盤庫并檢查唯一性。或者您甚至可以創建這樣的服務作為應用程式層服務。
讓我們不要忘記和/或委托 - 如果您使用關系資料庫,那么為什么不實作一個復合鍵,在這種情況下為Menumade from RestaurantIdand Name- 然后資料庫也會強制執行不變性。
獲取唯一的約束例外 - 不保存聚合,不發送事件等,您只需要在某處處理它。
這將是我的 goto 解決方案,否則只是擴展Restaurant聚合以包含Menu它的一部分。
同樣,這是基于意見的,有很多方法可以解決這個問題。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/355962.html
