3

我一直在寻找不同的方法CQRS samples,其中大多数使用不保存的命令处理程序UnitOfWork(即DataContext在 的情况下Entity Framework)。像这样的东西:

    public void Handle(Command message)
    {
        var course = Mapper.Map<Command, Course>(message);

        _db.Courses.Add(course);
    }

处理请求时,保存(和事务提交)通常在后台发生。

我从许多领先的 CQRS 专家那里看到了这种方法,但我从未听说过它的推理。

这种方法的最大问题是当您需要在处理程序调用返回后立即获取实体 ID(这种情况经常发生)。显然有一些方法可以解决它(即使用 Guid,从您的数据库中预先请求唯一的 Id 等),但看起来很笨拙。

但是这种方法的优点是什么?从理论上讲,如果我们每个请求有多个处理程序,则不进行多次数据库往返可能会有所帮助。但它不会发生很多。我想到的另一个优点是我们不必键入例行的 Save 调用并让它自动发生。这有点好,但它是否加重了 ID 生成问题?

4

2 回答 2

2

为什么 CQRS 命令处理程序不包括保存 UnitOfWork?

我认为它始于 Evans,领域驱动设计,第 6 章领域对象的生命周期

有很多技术可以应对数据库访问的技术挑战......

但即便如此,请注意丢失的内容。我们不再考虑领域模型中的概念。我们的代码不会与业务相关,它将操纵数据检索技术。

这个想法是,在代码的这一点上,我们正在使用域模型而不是查看数据模型

存储库减轻了客户端的巨大负担,它现在可以与一个简单的、意图揭示的界面对话,并根据模型询问它需要什么

埃文斯非常强调这一点,在交易的背景下

将事务控制权留给客户端。虽然 REPOSITORY 会插入和删除数据库,但它通常不会提交任何内容。例如,在保存后提交是很诱人的,但客户端可能具有正确启动和提交工作单元的上下文。如果 REPOSITORY 不动手,事务管理会更简单。

一些附加说明:

这种方法的最大问题是当您需要在处理程序调用返回后立即获取实体 ID(这种情况经常发生)。

这通常表明您正在解决错误的问题。请参阅 Marc de Graauw,Nobody Needs Reliable Messaging

于 2017-02-10T06:42:55.657 回答
1

命令处理程序的一个重要特性是它不返回任何内容(异常除外)。这是一个微妙的点,但是如果您知道所有命令处理程序都不返回任何内容,那么您可以节省大量代码并简化或制作更强大的代码库。

但是如果你没有返回任何东西,那么你就会遇到在进程开始时需要 id 的情况。我认为使用 GUID 是一个优雅的解决方案。

从数据库中预取唯一 ID 充满了问题,如果可能的话,我会避免这种方法。

以下是一些优点:

  1. 所有命令处理程序都有一个通用接口
  2. 因此,您可以编写支持所有命令处理程序的辅助代码。例如命令路由器、安全和权限检查、日志记录、性能监控、消息队列......
  3. 它可以显着减少您需要编写的代码量
  4. 它可以显着降低您需要编写的代码的复杂性
  5. 测试更容易,更健壮

这些只是我脑海中的一些。

为什么不包括一个工作单元?

你可以是简短的答案。但我喜欢将持久性的责任从处理程序中移出。处理程序可能会调用它,但实际的持久性是在其他地方完成的(在大多数情况下,我的偏好是在事件存储中)。

于 2017-02-09T09:02:39.677 回答