通知客户有关新创建的itemId的最佳做法

时间:2014-06-26 15:34:32

标签: java architecture domain-driven-design cqrs

我拥有DDD / CQRS应用程序。

我的问题涉及通过POST(Rest)处理项目创建。

CQRS(基于CQS原则)促进命令永远不会返回值 有查询。

所以我想知道如何处理Item创建的用例。

这是我当前的命令处理程序模式(示例的灯光(没有接口等)):

@Service
@Transactional
public CreateItem {

    public void handle(CreateItemCommand command) {
       Customer customer = customerRepository.findById(command.customerId);
       ItemId generatedItemId = itemRepository.nextIdentity();  //generating the GUID 
       customer.createItem(generatedItemId, .....); 
    }

}

通过阅读this文章,一个简单的方法是在命令中声明一个输出属性,填充在handle方法的末尾,如下所示:

        public void handle(CreateItemCommand command) {
           Customer customer = customerRepository.findById(command.customerId);
           ItemId generatedItemId = itemRepository.nextIdentity();  //generating the GUID 
           customer.createItem(generatedItemId, .....);
           command.itemId = generatedItemId;  //populating the output property  
        }

但是,我发现这种方法有一个缺点:   - 理论上,命令是不可变的

这个itemId将通过位置标头调用控制器(webapp)发送,状态为201或202(取决于我是否期望异步)。

另一种解决方案是让控制器通过访问存储库本身来初始化GUID,从而使命令不可变:

//in my controller: 
ItemId generatedItemId = itemRepository.nextIdentity();  //controller generating the GUID 
createItem.handle(command);
// setting here the location header (201-202) containing the URL to the newly created item with the using the previous itemId.

缺点:控制器(适配器层)直接访问存储库...,这是太低级别的IMO。

我的极端客户端是一个Javascript应用程序,我可能有另一个解决方案让Javascript本身生成一个GUID,并在将整个命令发送到服务器之前将CreateItemCommand与它一起提供。

优势:不再存在可能违反CQ(R)S指南的问题 缺点:应检查服务器端传递的id的有效性。虽然会有一个唯一的索引,可以防止在数据库中意外插入。

处理此问题的最佳(或仅仅是好的)策略是什么?

1 个答案:

答案 0 :(得分:2)

我是基于CQRS模式的CRM应用程序的开发人员。我倾向于认为命令是不可变的。该团队很早就决定,在客户端上生成所有ID以获得不可变命令。这是完全正常的,因为我们正在使用UUID。所以我们非常有信心,ID是有效的,没有ID冲突。到目前为止,我们采用了这种方法 - 我绝对可以推荐这个。在那种情况下,客户端只知道ID。

有时它会发生 - 特别是在手动测试中 - 使用相同的ID调度create命令两次。在这种情况下,事件存储中事件的添加失败(我们使用事件源),并且存在重复的键异常。异常传递给控制器​​。事实上,我们确实通过回调来返回命令执行的结果,即使它在大多数情况下只是“一切正常” - 所以没有抛出异常。命令验证也是这样完成的。我们使用命令总线概念来做到这一点。

我建议看看Axon框架。我们使用它,它提供了常见的构建块,它只是工作。也许你可以从中获得灵感!