2

我想通過使用DDD建模一個簡單的域。數據庫層是通過使用實體框架實現的,域對象是POCO。域具有具有名字,姓氏和用戶名屬性的用戶實體。因此,域定義了處理用戶資源庫的IRepository。DDD:將實體添加到存儲庫和handlig例外

現在在域邏輯中的一個要求是沒有兩個具有相同用戶名的用戶可以存在。所以當另一個具有相同用戶名的用戶已經存在時,試圖添加新用戶應該會引發異常。

IUnitOfWork unitOfWork = new UnitOfWork(); 
IRepository<User> users = unitOfWork.Users; 

User user1 = new User() { Username = "jsmith", FirstName = "John", LastName = "Smith" }; 
users.Add(user1); 
users.Save();  // ok, new user added to the underlying database 

User user2 = new User() { Username = "jsmith", FirstName = "Jim", LastName = "Smith" }; 
users.Add(user2); // exception here? 
users.Save();  // or exception here? 

這是一個代碼示例,應該添加到添加新用戶的WPF應用程序中。在這裏,UnitOfWork封裝了實體框架的DbContext對象。

我的問題是我該如何以及應該在哪裏強制執行此域規則?在嘗試將用戶添加到存儲庫或者調用Save()方法時應該拋出異常嗎?我應該創建域服務來添加新用戶,然後處理所有域邏輯規則嗎?

另外,我應該拋出什麼異常?我應該創建一些自定義域例外,如DuplicateUserException或類似的東西?

回答

1

db是該規則的最終執行者。現在,這是一個多用戶的應用程序?如果是這樣,那麼最實用的方法是依靠db,捕獲sql異常,然後拋出將被重定向到UI的businessrule異常(即將觸發錯誤消息)。

您可以在域級別驗證名稱是否已存在(通過服務是最有效的方式),但這可能會在併發環境中失敗。然而,這是一個單一用戶應用程序的優雅和乾淨的解決方案。而通過單用戶應用程序,我的意思是,所有的應用程序將一次爲一個用戶服務。如果你有一個WPF客戶端和一個Web服務,那是一個多用戶應用程序。

最好的辦法是讓持久性(在本例中爲db)處理這條規則,因爲它是確保沒有重複名稱的回購責任(存儲庫不是愚蠢的存儲桶,它是持久性的管理器),它也解決了併發問題。

請注意,我沒有提到EF,因爲它與db溝通的方式並不重要。如果明天你會切換到Azure數據庫,解決方案仍然是一樣的,只有具體的實施部分會有所不同。

+0

是的,這是一個多用戶應用程序,從某種意義上說,將會有不同用戶可以同時使用的WPF和ASP.NET MVC3前端。所以我們基本上是通過持久層實施域規則,如果我理解正確的話?那麼我應該把通用代碼添加到某種服務中,而不是複製粘貼上面寫在多個位置的代碼嗎?如果是這樣,該服務應該放在哪裏,並且是該應用程序還是該域或基礎架構服務?對不起,其他問題,但你真的幫助我提高我的理解! – matori82

+0

首先,當您構建應用程序以最終解決業務問題時,您的整個應用程序將執行業務規則。現在,該特定需求在存儲庫級別實施(通過db約束)。其他需求更適合其他地方,DDD棘手的部分是沒有硬規則,只有指導方針,其餘的由您決定。我會將新用戶放入域中,然後將該對象發送到要保存的回購。可以在UI或控制器級別完成簡單的驗證,在域級別執行更多規則,最後在持久級別執行唯一性約束 – MikeSW

1

我有最好的運氣與使用自定義的初始化,並指定唯一約束使用ExecuteSqlCommand,像這樣的數據庫:

public class MyInitializer 
    : DropCreateDatabaseIfModelChanges<MyContext> 
    // Or whichever base class you want to use. DropCreateDatabaseAlways<>, 
    // MigrateDatabaseToLatestVersion<>, etc. or even IDatabaseInitializer<> 
{ 
    public void InitializeDatabase(MyContext context) 
    { 
    // other initialization 
    context.Database.ExecuteSqlCommand("ALTER TABLE Users" + 
             "ADD CONSTRAINT UQ_Users_Username " + 
             "UNIQUE(Username)"); 
    } 
} 

這使綁定的邏輯數據庫。您也可以執行EntityTypeConfiguration<User>並對Validate方法執行檢查,但是您只需對每個驗證執行的數據庫執行ping操作即可進行檢查。

+0

對不起,我對EF不是很熟悉,你能解釋一下你的代碼嗎?您的示例中的此E-SQl查詢是否用於Code First的流暢API? – matori82