标签: domain-events

触发CQRS中其他域更改的域事件

在我看到的所有CQRS示例中,域事件触发了对读取模型的更新,但没有其他任何内容.但是,当您希望域事件在域中引起其他更改时呢?

例如,假设您有以下要求:

  • 单击"关闭帐户"按钮时,关闭该帐户
  • 当帐户被还清时,关闭帐户
  • 帐户关闭时,将帐户所有者标记为"特殊"

处理这个问题的最佳方法是什么?

  1. 使Account.Close()创建一个AccountClosed事件,并将所有者标记为"特殊"
  2. 创建一个AccountClosed处理程序,将所有者标记为"特殊"
  3. 创建一个AccountClosed处理程序,提交MarkOwnerAsSpecial命令
  4. 使关闭帐户的命令处理程序也将帐户所有者标记为"特殊"

domain-driven-design cqrs domain-events

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

CQRS和同步操作(如用户注册)

我正在采用DDD概念来设计我们的下一个项目,更具体地说是CQRS.

在阅读了很多东西后,我现在正试图实现一个简单的概念验证.

事情是我开始后就被困住了:p

我正在尝试将此方法应用于简单的用户注册过程,其中的步骤是:

  • 用户填写注册表并提交请求
  • 该应用程序创建用户
  • 该应用程序验证用户(自动登录)
  • 该应用程序向用户发送验证电子邮件
  • 该应用程序通过确认消息将用户重定向到其他位置

从实现的角度来看,到目前为止我得到的是:

  • 控制器操作将请求数据映射到RegisterCommand对象
  • 控制器操作要求命令总线处理RegisterCommand
  • 命令处理程序(UserService)"register"方法创建一个新的User对象(无论是通过新命令还是工厂对象)
  • 该模型引发了RegisterEvent
  • 命令处理程序要求存储库存储新的用户对象

就是这样,控制器动作不知道任何一个.

所以,我的猜测是,因为这个上下文中的所有东西都要同步完成(除了电子邮件发送),我可以使用直接/同步命令总线,并在控制器操作中,在命令总线调用之后,我可以查询对于只读用户(查询数据库),如果它存在假设一切顺利,那么我可以给用户一个确认消息.

自动登录过程由事件处理程序处理.

假设这是正确的,如果出现问题怎么办,如何通知用户正确的信息?

我们可以通过互联网找到的文章中经常使用一个常见的例子:客户使用过期的信用卡支付订单.系统接受请求,通知用户一切正常,但用户几分钟后收到一封电子邮件,告诉他无法处理他的订单.

嗯,在许多情况下,这种情况是可以接受的,但对于其他一些情况,这是不可能的.那么处理这些用例的例子在哪里?:p

谢谢 !

domain-driven-design cqrs domain-events

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

域事件处理程序 - 它们是否应该用于应用程序层问题?

在实现Domain事件时,事件处理程序应仅用于纯域关注; 您将与业务专家讨论的内容,或者是否可以被对域模型感兴趣的任何内容使用?

最好用一个简单的例子来解释这个问题,考虑一个Calendar应用程序来为员工安排工作.

我们可能会有以下域名事件......

AppointmentAdded AppointmentRemoved AppointmentContentChanged AppointmentMoved

我们有这些事件的处理程序,例如当约会被移动到员工工作时间之外的时间时,我们设置警告标志.

当然存在对这些事件感兴趣的应用程序问题,例如,当将约会添加到日历时,我们应该将其添加到工作单元,以便我们可以稍后提交更改.

这些应用程序问题是否应该是域事件的消费者,还是我们应该提出并处理单独的系统事件?

architecture domain-driven-design domain-events

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

域驱动设计和域事件

我是DDD的新手,我现在正在阅读文章以获取更多信息.其中一篇文章侧重于域事件(DE).例如,发送电子邮件是在执行一段代码时满足某些条件后引发的域事件.

代码示例显示了处理域事件的一种方法,然后是本段

请注意,上述代码将在与常规域工作相同的事务中的同一线程上运行,因此您应该避免执行任何阻止活动,例如使用SMTP或Web服务.相反,更喜欢使用单向消息传递与其他阻止活动的东西进行通信.

我的问题是

  1. 这是处理DE的一般问题吗?或者只是关注上述文章中的解决方案?
  2. 如果在事务中引发域事件并且系统不会同步处理它们,那么应如何处理它们?
  3. 当我决定序列化这些事件并让调度程序(或任何其他机制)执行它们时,当事务被回滚时会发生什么?(在事件中引发的文章事件是在事务中执行的代码)谁将取消它们(当它们不被持久化到数据库时)?

谢谢

domain-driven-design domain-events

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

Java中的域事件模式实现?

我正在寻找Udi Dahan的域事件模式和基础结构的简单Java实现,如本文所述.

这很简单,我已经实现了自己的解释,但是我是一个Java新手,并且不想因为缺乏语言经验而被任何错误所困扰.

我发现的唯一Java实现是在Jdon Framework中,但它对我目前的项目来说有点过于重要.

谢谢!

java design-patterns domain-driven-design domain-events

7
推荐指数
2
解决办法
4274
查看次数

序列化和反序列化域事件以在通用实现中从事件存储中保留和检索

我正在使用DDD与CQRS和事件采购.我需要在我的自定义实现中使用事件存储(特别是此事件存储)IEventStore来持久化并检索域事件,但我遇到了处理序列化/反序列化的方法时遇到困难.

这是我正在实现的接口:

public interface IEventStore
{
    Task<IEnumerable<IDomainEvent>> GetEventsAsync(Identity aggregateIdentity, Type aggregateType);

    Task PersistAsync(IAggregateRoot aggregateRoot, IEnumerable<IDomainEvent> domainEvents);
}
Run Code Online (Sandbox Code Playgroud)

在我的实现之外,IEventStore我可以将每个映射器都包含IDomainEvent在一些可序列化/可反序列化的EventDto或json字符串中.那不是问题.但这些是我的限制:

  • 我的域事件是实现的不可变对象IDomainEvent(即:没有setter)

  • 我的域事件并不总是以通用方式容易地序列化/反序列化.它们通常具有抽象或接口属性,因此我的域事件和一些可序列化对象(如字符串json或事件DTO)之间的具体映射器在我的IEventStore实现之外决定.

  • 我的IEventStore实现需要在一个通用的方式是,如果我添加新的域的事件类型,我应该不需要碰任何东西的范围内IEventStore实施

  • 我的IEventStore实现可以接收注入的一些特定实现IMapper<TSource, TDestination>,以便我可以使用它们在特定类型(而不是接口)之间进行序列化/反序列化.

    public interface IMapper<in TSource, out TDestination>
    {
        TDestination Map(TSource source); // I have implementations of this if needed
    }
    
    Run Code Online (Sandbox Code Playgroud)

以下是我的尝试:

public class MyEventStore
    : IEventStore
{
    private readonly IStreamNameFactory _streamNameFactory;
    private readonly …
Run Code Online (Sandbox Code Playgroud)

c# reflection serialization domain-events event-store

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

具有持久性无知对象的持久性和域事件

我一直在研究域驱动设计和域事件.我非常喜欢这些事件提供的关注点的分离.我遇到了持久化域对象和提升域事件的问题.我想在域对象中引发事件,但我希望它们是持久性无知的.

ShoppingCartService用这种Checkout方法创建了一个基本的:

public void Checkout(IEnumerable<ShoppingCartItem> cart, Customer customer)
{
    var order = new Order(cart, customer);

    _orderRepositorty.Add(order);
    _unitOfWork.Commit();
}
Run Code Online (Sandbox Code Playgroud)

在此示例中,构造函数Order将引发OrderCreated可由某些处理程序处理的事件.但是,我不希望在实体尚未持久化或持久化以某种方式失败时引发这些事件.

为了解决这个问题,我找到了几个解决方案:

1.提升服务中的事件:

我可以在服务中引发事件,而不是在域对象中引发事件.在这种情况下,该Checkout方法会引发OrderCreated事件.这种方法的缺点之一是,通过查看Order域对象,不清楚哪些事件是由哪些方法引发的.此外,开发人员必须记住在其他地方创建订单时提出事件.感觉不对劲.


2.队列域事件

另一个选项是对域事件进行排队,并在保持成功时引发它们.这可以通过一个using声明来实现,例如:

using (DomainEvents.QueueEvents<OrderCreated>())
{
    var order = new Order(cart, customer);

    _orderRepositorty.Add(order);
    _unitOfWork.Commit();
}
Run Code Online (Sandbox Code Playgroud)

QueueEvents<T>方法将布尔值设置为,true并且该DomainEvents.Raise<T>方法将对事件进行排队,而不是直接执行它.在dispose回调中QueueEvent<T>,执行排队事件,确保已经发生持久化.这似乎相当棘手,它需要服务知道域对象中引发了哪个事件.在我提供的示例中,它也只支持一种类型的事件,但是,这可以解决.


3.坚持域名活动

我可以使用域事件来持久化对象.这似乎没问题,除了持久化对象的事件处理程序应首先执行这一事实,但我在某处读到域事件不应该依赖于特定的执行顺序.也许这不是那么重要,域事件可能以某种方式知道处理程序应该执行的顺序.例如:假设我有一个定义域事件处理程序的接口,实现将如下所示:

public class NotifyCustomer : IDomainEventHandler<OrderCreated>
{
   public void Handle(OrderCreated args)
   {
       // ... …
Run Code Online (Sandbox Code Playgroud)

c# asp.net-mvc persistence domain-driven-design domain-events

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

DDD 中是否存在应用程序事件术语?

领域事件在 DDD 中众所周知,可以在聚合根或领域服务中发布。我的问题是,域事件可以在应用程序服务/用例中发布吗?

例如,简化。我有一个名为 的应用程序服务UseCaseA,它执行调用一些聚合根的各种操作。如果我想在该用例结束时引发一个事件,我可以UseCaseAFinished在此应用程序服务中发布该事件吗?它是领域事件还是应该称为应用程序事件?DDD 中是否存在应用程序事件术语?

提前致谢。

domain-driven-design terminology domain-events

6
推荐指数
2
解决办法
1554
查看次数

领域驱动设计 (DDD):领域事件处理程序 – 将它们放置在哪里?

我对在基于六边形架构的应用程序中处理域事件的位置感到困惑。我说的是有界上下文内部域事件,而不是上下文间集成/应用程序/公共事件。

背景

据我了解,应用程序逻辑(即用例逻辑、工作流逻辑、与基础设施的交互等)是命令处理程序所属的地方,因为它们特定于特定的应用程序设计和/或 UI 设计。然后命令处理程序调用域层,所有域逻辑都驻留在其中(域服务、聚合、域事件)。领域层应该独立于特定的应用程序工作流程和/或 UI 设计。

在许多资源(博客、书籍)中,我发现人们在应用程序层中实现域事件处理程序,类似于命令处理程序。这是因为域事件的处理应该在其自己的事务中完成。由于它可能会影响其他聚合,因此必须首先通过基础设施加载这些聚合。然而,关键点是:领域事件被分解并变成对聚合的一系列方法调用。这个重要的转换仅存在于应用层。

问题

我认为关于哪些领域事件会对其他聚合产生什么影响的知识是领域知识本身的一个组成部分。如果我要删除除域层之外的所有内容,那么这些知识不应该保留在某个地方吗?在我看来,我们应该将域事件处理程序直接放置在域层本身中:

  • 它们可以是域服务,接收域事件和可能受其影响的聚合,并将域事件转换为一个或多个方法调用。

  • 它们可以是聚合本身的方法,直接消耗整个域事件(即签名包含域事件类型)并对其执行任何操作。

当然,为了加载受影响的聚合,我们仍然需要在应用层有一个相应的处理程序。该处理程序仅启动一个新事务,加载感兴趣的聚合并调用域层。

由于我从未在任何地方看到过这一点,我想知道我是否对 DDD、领域事件或应用程序层和领域层之间的差异有什么误解。

编辑:示例

让我们从这种常用的方法开始:

// in application layer service (called by adapter)
public void HandleDomainEvent(OrderCreatedDomainEvent event) {
    var restaurant = this.restaurantRepository.getByOrderKind(event.kind);
    restaurant.prepareMeal(); // Translate the event into a (very different) command - I consider this important business knowledge that now is only in the application layer.
    this.mailService.notifyStakeholders();
}
Run Code Online (Sandbox Code Playgroud)

换成这个怎么样?

// in application layer service (called by adapter)
public void HandleDomainEvent(OrderCreatedDomainEvent event) {
    var …
Run Code Online (Sandbox Code Playgroud)

domain-driven-design business-logic hexagonal-architecture domain-events

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

域事件是否可以在不属于聚合状态更改 (DDD) 的情况下发出

我想知道如果域事件不是聚合状态更改的自然结果,如何实现它(在 DDD 中)。

我借用这篇文章的例子。

因此,假设我们需要一个像:TemperatureWasMeasured这样的事件,它可能是我们所做的某些建模的产物(例如在事件风暴会话中)。

此事件感觉像是某些读取操作的产物,而不是某些聚合的实际状态更改。

所以问题是: 这个事件在哪里以及如何有意义地被发射?

我们可以创建一个实体或聚合,它可以有一个状态来计算读取次数,以便作为状态更改发出。但这真的有必要吗?

在现有的资源中,“领域事件”的定义似乎没有提到状态变化,而只是在领域中发生了一些事情。

那么测量的动作(在非量子力学环境中)被认为是一个域事件,就像TemperatureWasMeasured事件一样?

如果有人能澄清这些问题那就太好了,因为似乎没有明确的答案。

events domain-driven-design aggregate event-driven domain-events

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