2011-02-10 122 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

我认为你的模型存在一个基本问题。如果我理解正确,网站是用户聚合组的一部分。这意味着网站实例不具有全局范围,仅在属于用户的情况下才有意义。

但是现在,当用户想要添加新网站时,首先要在创建新网站之前检查“网站是否存在于数据库中”。这意味着网站实际上具有全球范围。否则,无论用户何时请求新网站,您都会为该特定用户创建一个新网站,该网站在该用户的范围内有意义。在这里,您拥有共享的网站,因此在许多用户的范围内具有意义,因此不属于用户聚合的一部分。

修复您的模型,您将解决您的查询困难。