标签: domain-driven-design

DDD:在何处实施域服务

域服务实现应位于DDD项目结构中的什么位置?如果我们有IDomainInterfaceDomainInterface实施,应DomainInterface执行驻留在解决方案/项目的基础设施或核心/域的一部分?

domain-driven-design project-structure

1
推荐指数
1
解决办法
2055
查看次数

如何“查询”聚合以查看命令是否可以执行

我有一个电子邮件草稿与以下命令的聚合根:addToRecipientaddCcRecipientaddBccRecipientupdateBodyTextuploadAttachmentremoveAttachment并在UI我想禁用SEND按钮,如果还没有准备好要发送的草案(即至少有上收件人和正文中有文字)。我知道我不允许查询聚合,但这是唯一可以告诉我可以发送或不能发送电子邮件的消息。

如果我要应用我对事件源和CQRS的了解,则聚合将发出一个EmailIsReadyToBeSent事件,而我的UserEmailDrafts读取模型将选择该事件并以某种方式更新UI,但是,我将必须在每个命令之后检查并发送取消事件,即EmailIsNotReadyToBeSent

这感觉很复杂,您怎么看?

events domain-driven-design aggregateroot cqrs event-sourcing

1
推荐指数
1
解决办法
307
查看次数

使用RPC样式的API而不是REST的CQ(R)S

我正在一个基于PHP / JS的项目中,在这里我想在后端介绍域驱动设计。我发现命令和查询比CRUD是表达我的公共领域的更好方法,因此我喜欢遵循CQS原则构建基于HTTP的API。这不是安静的CQRS,因为我想在命令和查询端使用相同的模型,但是许多原理是相同的。对于API文档,我使用Swagger。

我找到了一篇文章,该文章通过REST资源(https://www.infoq.com/articles/rest-api-on-cqrs)公开了CQRS 。他们使用5LMT来区分不同的命令,而Swagger不支持。此外,通过将CQS放到面向资源的REST API中,我是否不会失去意图显示接口的好处?我没有找到任何文章或产品直接通过基于HTTP的后端公开命令和查询。

所以我的问题是:直接通过API公开命令和查询是否是一个好主意。它看起来像这样:

POST /api/module1/command1
GET /api/module1/query1
...
Run Code Online (Sandbox Code Playgroud)

它不是REST,但我看不到REST如何为表带来任何好处。维护REST资源将引入另一个模型。而且,在URL中具有命令和查询将允许使用诸如路由框架和访问日志之类的功能。

rest rpc domain-driven-design cqrs

1
推荐指数
1
解决办法
914
查看次数

聚合和DDD

我正在开发一个应用DDD原则的项目,我创建了一个类聚合(Account),它将包含类(代理)和(代理),其中(Account)在数据库中有表.我的问题是:

我需要为我的每个实体(帐户,代理和代理)创建一个Repository类和一个Service类,或者我应该创建AccountRepository并在其中执行3个类的插入和搜索?

c# domain-driven-design aggregation

1
推荐指数
1
解决办法
66
查看次数

在并发编辑环境中为子实体强制实施不变量

鉴于子集合不能超过x个项目的不变量,域名如何保证在并发/ Web环境中强制实施这种不变量?让我们看一个(经典)示例:

我们有一个ManagerEmployees.(假设的)不变量表明经理不能有超过七个直接报告Employee.我们可以这样(天真地)实现这样:

public class Manager {

    // Let us assume that the employee list is mapped (somehow) from a persistence layer
    public IList<Employee> employees { get; private set; }

    public Manager(...) {
        ...
    }

    public void AddEmployee(Employee employee) {

        if (employees.Count() < 7) {
            employees.Add(employee);
        } else {
            throw new OverworkedManagerException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

直到最近,我才认为这种方法足够好.然而,似乎还有就是它使数据库来存储边缘的情况下超过七名员工,从而打破不变.考虑这一系列事件:

  1. 人员A在UI中编辑管理员
    (内存中有6名员工,数据库中有6名员工)
  2. 人员B在UI中编辑管理员
    (内存中有6名员工,数据库中有6名员工)
  3. B人员添加员工并保存更改
    (内存中有7名员工,数据库中有7名员工)
  4. 人员A添加员工并保存更改
    (内存中有7名员工,数据库中有8名员工)

当再次从数据库中提取域对象时,Manager …

c# domain-driven-design

1
推荐指数
1
解决办法
100
查看次数

应用程序架构 - User.CreatePost(Post)或PostsService.CreatePost(Post,User)?

基本上,我的应用程序将像stackoverflow一样工作,你登录和发布的东西,其他人来和互动.

考虑DDD术语,并试图避免贫血模型,我现在面临这样的决定:我的User实体是否应该掌握创建任何更新+删除+检索他的帖子所需的知识,或者我应该回到旧模式我有一个"发布业务服务",将获得UserDTO参考,PostDTO并做一切?

详细信息:
- 我相信我需要某种帖子服务,因为主页面需要列出所有帖子,管理员用户将能够删除任何帖子... -
理想情况下,只有User实体(和其他人继承)从它)应该能够创建帖子
- 我不知道我将如何处理授权(想想阻止垃圾邮件发送者和其他人) -
也许这应该是由User.CreatePost(postDTO)?触发的域名服务?

architecture domain-driven-design anemic-domain-model

1
推荐指数
1
解决办法
72
查看次数

CQRS实施细节

我正在使用CQRS和Event-Sourcing实施微服务.我已经看到了CQRS的不同实现,这些实现非常复杂.

我已经理解和实现的是我已经为Read(Query)和Write(Command)创建了两个模型,read模型有一个物化视图,而write模型使用了Database,现在每当发生更新时,write模型都会更新数据库并生成一个事件,并将详细信息记录到读取模型已订阅的事件存储中,并且读取模型通过读取事件来更新其物化视图.

我的问题是这种模式是否依赖于CQRS和事件采购的基础?

domain-driven-design cqrs event-sourcing

1
推荐指数
1
解决办法
249
查看次数

ValueObject的抽象

我正在尝试使用ValueObject学习编码.我有关于VO的抽象实现的问题,而子类扩展了它.孩子们只会实现给定值的验证方法(电子邮件,用户名等).我的第一个VO看起来在下面是业务规则,这些规则在构造函数中进行验证.

final class Email {
    private $email;

    public function __construct(string $email)
    {
        $this->validateEmail($email);

        $this->email = $email;
    }

    public function value() : string
    {
        return $this->email;
    }

    private function validateEmail(string $email) : void
    {
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            throw new IncorrectEmailException();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当我写第二个VO时,我发现了一些不同的模式,只有验证规则(方法validate).所以我想到了一些抽象类实现模式,让child改进验证规则.

abstract class ValueObject {

    protected $value;

    public function __construct($value)
    {
        $this->validate($value);

        $this->value = $value;
    }

    public function value()
    {
        return $value;
    }

    abstract protected function validate($value) : void;
}

final class Email extends ValueObject …
Run Code Online (Sandbox Code Playgroud)

php oop inheritance abstract-class domain-driven-design

1
推荐指数
2
解决办法
210
查看次数

使用DDD和AutoMapper,您如何在单个工作单元内的多个服务中处理相同的聚合根?

我正在尝试在非基于Web的项目中学习和实现域驱动设计.我有一个主循环,它将在单个工作单元中对很多实体执行多个过程.除非整个循环的工作成功,否则我不希望任何更改被持久化.我正在使用AutoMapper将持久性模型转换为存储库中的域模型,我的服务正在使用存储库在工作之前检索数据.

有一些DDD元素与我的项目不能很好地工作,我希望有人可以告诉我整个过程有什么问题.

以下是我正在努力解决的DDD想法:

  • 当进程涉及多个聚合根相互交互时,应使用域服务
  • 您应该将聚合根ID传递给域服务,然后使用存储库加载它们
  • 存储库应该返回它从映射的持久性模型构造的域模型(在这种情况下,我使用的是AutoMapper)

这是我正在尝试做的一个例子.

using (var scope = serviceProvider.CreateScope())
            {
                var unitOfWork = scope.ServiceProvider.GetService<IUnitOfWork>();
                var aggregate1Repo = scope.ServiceProvider.GetService<IAggregate1Repository>();
                var aggregate2Repo = scope.ServiceProvider.GetService<IAggregate2Repository>();
                var aggregate3Repo = scope.ServiceProvider.GetService<IAggregate3Repository>();
                var firstService = scope.ServiceProvider.GetService<IFirstService>();
                var secondService = scope.ServiceProvider.GetService<ISecondService>();

                var aggregate1 = aggregate1Repo.Find(1); //First copy of aggregate1
                var aggregate2 = aggregate2Repo.Find(1000); 
                var aggregate3 = aggregate3Repo.Find(123); 

                aggregate1.DoSomeInternalWork();

                firstService.DoWork(aggregate1.Id,aggregate2.Id); 
                secondService.DoWork(aggregate1.Id,aggregate3.Id);

                aggregate1Repo.Update(aggregate1);
                unitOfWork.Commit();
            }
Run Code Online (Sandbox Code Playgroud)

Aggregate1Repo:

public class Aggregate1Repository
{
    private readonly AppDBContext _dbContext;
    private IMapper _mapper;

    public Aggregate1Repository(AppDBContext context, IMapper mapper)
    {
        _dbContext = context; …
Run Code Online (Sandbox Code Playgroud)

c# domain-driven-design repository-pattern automapper asp.net-core

1
推荐指数
1
解决办法
1337
查看次数

DDD-引用聚合外部的实体

这是我在DDD上的第一次尝试,我想获得有关建模问题的建议。

这是我的专长:多所学校的管理。

  • 所学校有多名学生老师 ...
  • 对于一所学校,有(每年)新学年(其中有一个值对象持有2017-2018的实例)
  • 班级学生分数与学年相关(例如,学生A可以在2017-2018学年进入C1班级,并在2018-2019学年进入C2班级)

我的第一个疑问是对schoolYear的建模。

我已经将学校实体作为根集合。我的第一个方法是让学校聚合处理增加的schoolYear(这样我就可以避免重复,或者可以创建下一个schoolYear,……)

=> schoolYear学校总数的一部分

但是后来我不得不对课程学生分数进行建模……这取决于学校年份

因此,在我的所有班级中,我必须保留对schoolYear的引用……这违反了规定

“无法从外部汇总中引用内部实体。”

在我的领域中,很多实体都取决于特定的SchoolYear。也许应该是一个汇总……

另一方面,给定班级schoolYear用于搜索班级。

我可以获取有关此建模问题的一些建议吗?

另一个有疑问的问题是关于schoolYear的身份。

  • 选项A:按原样生成UUID,并保留schoolId + year作为属性
  • 选项B:Id是schoolIdyear,因此我们不能为同一所学校和同一年两次创建同一所学校的Year

有什么建议吗?

非常感谢您帮助我进入DDD世界!

entity domain-driven-design reference aggregateroot

1
推荐指数
1
解决办法
661
查看次数