Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/svg/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Domain driven design 域驱动设计:每个聚合根的存储库?_Domain Driven Design_Repository - Fatal编程技术网

Domain driven design 域驱动设计:每个聚合根的存储库?

Domain driven design 域驱动设计:每个聚合根的存储库?,domain-driven-design,repository,Domain Driven Design,Repository,我正试图找出如何实现以下目标: User can have many Websites 在向用户添加新网站之前,我需要做的是获取网站URL并将其传递给一个方法,该方法将检查数据库中是否已经存在该网站(另一个用户关联了相同的网站),或者是否创建新记录 无论您使用什么存储库方法,都应该能够以某种方式指定标准。因此,搜索与相关网站关联的用户-如果搜索未返回任何用户,则该网站未被使用 例如,您可以添加具有以下签名的方法(或者将查询对象传递为): 该方法应生成大致如下所示的SQL: select u.u

我正试图找出如何实现以下目标:

User can have many Websites

在向用户添加新网站之前,我需要做的是获取网站URL并将其传递给一个方法,该方法将检查数据库中是否已经存在该网站(另一个用户关联了相同的网站),或者是否创建新记录 无论您使用什么存储库方法,都应该能够以某种方式指定标准。因此,搜索与相关网站关联的用户-如果搜索未返回任何用户,则该网站未被使用

例如,您可以添加具有以下签名的方法(或者将查询对象传递为):

该方法应生成大致如下所示的SQL:

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

这应该与直接查询
网站
表一样高效;无需将所有用户和网站记录加载到内存中。让关系数据库承担重任,让存储库实现(或对象关系映射器)处理转换。

一种策略是实现一个可以验证约束的服务

public interface IWebsiteUniquenessValidator 
{
    bool IsWebsiteUnique(string websiteUrl);
}
然后你必须实现它,你如何做到这一点将取决于我不知道的因素,但我建议不要担心通过域。简单一点,这只是一个查询(*-我将在底部添加到这个查询中)

然后,将其“注入”到需要的方法中。我之所以说“注入”,是因为我们将从域外部将其提供给域对象,但是。。我们将使用方法参数而不是构造函数参数来实现这一点(以避免要求我们的实体由IoC容器实例化)

无论用户及其存储库的使用者是什么(如果是服务类或CommandHandler),都可以提供唯一性验证器依赖关系。此使用者应该已经通过IoC连接,因为它将使用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) {
          //....
        }
    } 


}
*我提到了简化验证和避免域

我们构建域来封装修改数据所涉及的复杂行为

经验表明,围绕更改数据的需求与围绕查询数据的需求大不相同


这似乎是您正在经历的一个痛点,因为您正试图强制读取通过写入系统

为了减轻这些痛点,可以将数据的读取与域、写入端分开


是该技术的名称。我只想说,当我在CQR的上下文中查看DDD时,一大堆灯泡发出咔哒声。我强烈建议您尝试理解CQR的概念。

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

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


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

是的,但是当一个网站没有用户(一对多)就无法存在时,我如何搜索与具有特定URL的网站关联的用户?@eb,我只是建议做一些简单的事情,比如
从用户u加入网站w上选择u.UserId,w.UserId=u.UserId,其中w.Url=@Url
(但由您的存储库用于指定标准的习惯用法来调节)。@Jeff Sternal,我想您弄错了。在添加具有相同URL的新网站并将其与用户关联之前,我想检查数据库中是否有任何用户具有关联的具有相同URL的网站记录。@ebb:该查询将完全执行此操作。如果任何用户有一个带有该URL的网站,它将返回一些内容。如果没有用户与该用户有一个网站,它将不会返回任何记录。@Jeff Sternal-哦,是的。。我的错。。但是,这个查询不会在用户表和网站表中循环吗?“这是一个你正在经历的痛点,因为你正试图通过一个写系统来强制读”——说得好!似乎90%对DDD持怀疑态度的问题都围绕着这个问题。(话虽如此,我认为在聚合的存储库中解决这一特定问题没有任何困难。)您将这种类型的验证称为什么样的“模式”?我以前从未见过将验证类注入实体方法。这不会污染域实体吗?我的意思是-不是在这种情况下,但你可以有很多复杂的验证。你用这种方式处理所有的验证吗?还有,关于CQR。这确实很有趣,但如果您的系统不是企业级的,那么这似乎需要做很多工作。我记得我读过Greg Young说过,它只适用于非常大的系统,这些系统将以各种方式进行扩展。你怎么认为?如果我错了,请纠正我。我并不是真的把“模式”叫做什么。这似乎只是解决如何在需要时提供对正确数据的访问而不降低效率或违反聚合根或存储库的某些原则这一难题的一种方法。另一种方法是在DB中使用唯一性约束并捕获异常。验证在同一实体的许多不同上下文中进行。有时候,部分内容不能很好地融入实体,比如验证,它通常需要访问额外的数据,因此我将数据块分解到服务中,通常的动机是需要为这些数据块提供依赖关系。一个目标
public class WebsiteUniquenessValidator : IWebsiteUniquenessValidator
{
 //.....
}
public class User 
{
    public void AddWebsite(string websiteUrl, IWebsiteUniquenessValidator uniquenessValidator) 
    {
        if (!uniquenessValidator.IsWebsiteUnique(websiteUrl) {
            throw new ValidationException(...);
        }

        //....
    }
}
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) {
          //....
        }
    } 


}