2011-02-10 90 views
4

我試圖找出如何實現以下目標:域驅動設計:每個聚合根的存儲庫?

User can have many Websites 

我需要添加一個新的網站給用戶之前做的,是把網站的網址,並把它傳遞到這將方法檢查網站是否已經存在於數據庫中(另一個用戶有相同的網站)或是否創建新記錄。 < =原因在於是創建新的縮略圖還是使用現有的縮略圖。

問題是,存儲庫應該是每聚合根,這意味着我不能做我上面解釋的? - 我可能首先獲得數據庫中的所有用戶,然後foreach用if語句檢查用戶是否擁有具有相同URL的網站記錄,但這會導致無盡的和緩慢的過程。

回答

2

無論您使用哪種存儲庫方法,您都應該能夠以某種方式指定標準。因此,搜索與相關網站相關的用戶 - 如果搜索沒有返回任何用戶,則該網站未被使用。

例如,您可以添加一個方法具有以下簽名(或您要傳遞一個查詢對象爲described in this article):

User GetUser(string hasUrl); 

這種方法應該或多或少像這樣生成的SQL:

select u.userId 
from User u 
join Website w 
on  w.UserId = u.UserId 
where w.Url = @url 

這應該與直接查詢Website表一樣有效;無需將所有用戶和網站記錄加載到內存中。讓你的關係數據庫完成繁重的任務,讓你的倉庫實現(或者對象關係映射器)處理翻譯。

+0

是的,但是當一個網站無法在沒有用戶的情況下存在(一對多)時,我將如何搜索與具有特定URL的網站相關聯的用戶? – ebb 2011-02-10 22:24:47

+0

@ebb,最終,我只是提出了一些簡單的選擇:從用戶u選擇u.UserId加入w.UserId = u.UserId的網站w其中w.Url = @ url`(但由您的存儲庫的成語指定標準)。 – 2011-02-11 01:54:36

0

一種策略是實施可以驗證約束的服務。

public interface IWebsiteUniquenessValidator 
{ 
    bool IsWebsiteUnique(string websiteUrl); 
} 

這樣您就可以實現它,你怎麼做,這將取決於多種因素,我不知道,但我建議不要擔心通過域去。簡單一點,它只是一個查詢(* - 我會在底部添加)。

public class WebsiteUniquenessValidator : IWebsiteUniquenessValidator 
{ 
//..... 
} 

然後,「注入」到需要它的方法中。我說「注入」是因爲我們將它從域外提供給域對象,但是..我們將使用方法參數而不是構造函數參數來實現(爲了避免要求我們的實體被我們的Io​​C容器實例化)。

public class User 
{ 
    public void AddWebsite(string websiteUrl, IWebsiteUniquenessValidator uniquenessValidator) 
    { 
     if (!uniquenessValidator.IsWebsiteUnique(websiteUrl) { 
      throw new ValidationException(...); 
     } 

     //.... 
    } 
} 

無論你的用戶和信息庫的消費者 - 如果這是一個服務類或CommandHandler - 可以提供獨特的驗證依賴。該消費者應該已經通過國際奧委會有線了,因爲它會消耗UserRepository:

public class UserService 
{ 
    private readonly IUserRepository _repo; 
    private readonly IWebsiteUniquenessValidator _validator; 

    public UserService(IUserRepository repo, IWebsiteUniquenessValidator validator) 
    { 
     _repo = repo; 
     _validator = validator; 
    } 

    public Result AddWebsiteToUser(Guid userId, string websiteUrl) 
    { 
     try { 
      var user = _repo.Get(userId); 
      user.AddWebsite(websiteUrl, _validator); 
     } 
     catch (AggregateNotFoundException ex) { 
      //.... 
     } 
     catch (ValidationException ex) { 
      //.... 
     } 
    } 


} 

*我提到做驗證簡單,避免域。

我們構建域來封裝與修改數據有關的常常複雜的行爲。

什麼經驗表明,關於數據變化的要求與查詢數據的要求有很大不同。

這似乎是你遇到的一個痛點,因爲你試圖強制讀取通過寫入系統。

爲了減輕這些痛點,可以從寫入端分離數據從域中讀取數據。

CQRS是該技術的名稱。我只是說,一旦我在CQRS的上下文中查看DDD,就會點擊一大堆燈泡。我強烈建議試着理解CQRS的概念。

1

我認爲你的模型存在一個基本問題。如果我理解正確,網站是用戶聚合組的一部分。這意味着網站實例不具有全局範圍,僅在屬於用戶的情況下才有意義。

但是現在,當用戶想要添加新網站時,首先要在創建新網站之前檢查「網站是否存在於數據庫中」。這意味着網站實際上具有全球範圍。否則,無論用戶何時請求新網站,您都會爲該特定用戶創建一個新網站,該網站在該用戶的範圍內有意義。在這裏,您擁有共享的網站,因此在許多用戶的範圍內具有意義,因此不屬於用戶聚合的一部分。

修復您的模型,您將解決您的查詢困難。