我一直在查看不同的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代问题?
答案 0 :(得分:1)
命令处理程序的一个重要特性是它不会返回任何内容(例外情况除外)。这是一个微妙的观点,但是如果你知道所有的命令处理程序都不会返回任何内容,那么你可以节省大量的代码并简化和建立更强大的代码库。
但是如果你没有返回任何东西,那么你就有了在进程开始时需要id的情况。我认为使用GUID是一种优雅的解决方案。
从数据库预先获取唯一身份证件充满了问题,如果可能的话,我会避免这种做法。
以下是一些优点:
这些只是我头脑中的一小部分。
为什么不包括一个工作单元?
你可以是简短的回答。但我喜欢将持久性的责任移出处理程序。处理程序可以调用它,但实际的持久性在其他地方完成(我的偏好在大多数情况下是在事件存储中)。
答案 1 :(得分:1)
为什么CQRS命令处理程序不能保存UnitOfWork?
我认为它始于埃文斯,Domain Driven Design,第6章域对象的生命周期。
有许多技术可以解决数据库访问的技术难题......
但即便如此,请注意丢失的内容。我们不再考虑域模型中的概念。我们的代码将不会就业务进行沟通,它将操纵数据检索技术。
我们的想法是,在代码的这一点上,我们正在使用域模型,而不是查看数据模型。
A REPOSITORY解除了客户的巨大负担,现在可以通过一个简单的,有意图的界面进行交流,并根据模型询问它需要什么
在交易的背景下,埃文斯非常重视这一点
将交易控制留给客户。虽然REPOSITORY将插入数据库并从数据库中删除,但它通常不会提交任何内容。例如,在保存之后提交是很诱人的,但是客户端可能具有正确启动和提交工作单元的上下文。如果REPOSITORY保持不动,交易管理将更加简单。
一些补充说明:
这种方法的最大问题是在返回处理程序调用之后需要获取实体ID的情况(这种情况发生了很多)。
这通常表明你正在解决错误的问题。见Marc de Graauw,Nobody Needs Reliable Messaging。