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

时间:2017-02-08 10:34:17

标签: .net cqrs mediatr

我一直在查看不同的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 Save并让它自动发生。它有点不错,但它是否超重了Id代问题?

2 个答案:

答案 0 :(得分:1)

命令处理程序的一个重要特性是它不会返回任何内容(例外情况除外)。这是一个微妙的观点,但是如果你知道所有的命令处理程序都不会返回任何内容,那么你可以节省大量的代码并简化和建立更强大的代码库。

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

从数据库预先获取唯一身份证件充满了问题,如果可能的话,我会避免这种做法。

以下是一些优点:

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

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

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

答案 1 :(得分:1)

  

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

我认为它始于埃文斯,Domain Driven Design,第6章域对象的生命周期

  

有许多技术可以解决数据库访问的技术难题......

     

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

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

  

A REPOSITORY解除了客户的巨大负担,现在可以通过一个简单的,有意图的界面进行交流,并根据模型询问它需要什么

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

  

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

一些补充说明:

  

这种方法的最大问题是在返回处理程序调用之后需要获取实体ID的情况(这种情况发生了很多)。

这通常表明你正在解决错误的问题。见Marc de Graauw,Nobody Needs Reliable Messaging