2

我很難找出實現業務規則驗證的最佳方法,依賴於存儲在數據庫中的數據。在下面的簡化示例中,我想確保Username屬性是唯一的。DDD - 實體的存儲庫相關驗證

public class User() { 
    public int Id { get; set; } 
    public string Name { get; set; } 
    public string Username { get; set; } 
    public string Password { get; set; } 
    public string GenerateRandomPassword() { 

    } 
} 

public interface IUserRepository : IRepository<User> 
{ 
    bool UsernameTaken(string username); 
} 

public interface IUnitOfWork : IDisposable 
{ 
    void Commit(); 
    IUserRepository Users { get; } 
} 

我已經讀了很多關於不同的方式實現這一目標的,包括注射到庫實體的東西(並防止它會處於無效狀態),創建一個擴展方法等

但是我不認爲這些都是最好的方法。

因此,我決定使用應用程序服務來編排使用規範的實體驗證。

public class CreateUserService : ICreateUserService 
{ 
    private readonly IUnitOfWork _uow; 

    public CreateUserService(IUnitOfWork uow) 
    { 
     _uow = uow; 
    } 

    public User Create(User user) 
    { 
     var usernameAvailableSpecification = new UsernameAvailableSpecification(_uow.Users); 

     if (!usernameAvailableSpecification.IsSatisfiedBy(user)) 
     { 
      throw new ValidationException("Username already taken"); 
     } 

     user.GenerateRandomPassword(); 

     _uow.Users.Store(user); 
     _uow.Commit(); 

     return user; 
    } 
} 

起初,它看起來不錯。但是單元測試很難,因爲服務與規範實現緊密結合,必須手動處理規範的依賴關係。我也想過抽象規範,但我不確定我是否是正確的道路。

我也有可能開始犯錯,因爲實際上我正在學習DDD,但仍然沒有清楚地知道哪一層應該負責這種驗證。

任何幫助,將不勝感激。

回答

3

這幾乎是我如何建模它,除了我將使CreateUserService成爲一個域服務(並在單獨的應用程序服務中處理工作單元)。採用這種方法,我不會太擔心域服務和規範之間的緊密耦合,因爲用戶名的唯一性似乎是源於實際業務領域的業務規則(這裏,「用戶和身份驗證」有界的上下文) 。

如果您仍然害怕CreateUserService與規範之間的緊密耦合,您的確可以進一步提取規範。似乎是合法的,但請記住YAGNI原則。

+0

謝謝你的回答。 我試過了你建議成功的方法。 另外,我接受它作爲答案。 再次感謝您。 – otaviosoares 2014-09-02 16:50:32