你好,
感谢您在CQRS上撰写本文。 我正在尝试了解实现的外观,并且正在研究示例。 该示例中提供的示例存储库代码看起来与除命名约定外通常如何编写存储库相似。 例如,我认为下面给出的存储库与ProductsCommandHandler
,可能的不同之处在于这里通常没有我们要添加的GetProduct
。 你能解释一下我没到这里吗?
public class ProductRepository {
void AddNewProduct(Product newProduct) {
...
}
void RateProduct(int productId, int userId, int rating) {
var product = repository.Find(productId);
if (product != null)
{
product.RateProduct(userId, rating);
repository.Save(product);
}
}
}
⚠请勿编辑此部分。
@martinmthomas谢谢您的提问! 我们将审查并提供适当的更新。
@MikeWasson在这里有什么想法吗?
AB#160217-感谢您的举报-此问题正在审核中
@martinmthomas实际上,命令处理程序不是存储库。 它使用一个存储库。
命令处理程序旨在“在适当的情况下处理实际命令”。 在示例中, ProductsCommandHandler
类在其构造函数中收到IRepository<Product>
。
假设用户将产品5555评分为4星。
{"product":"5555","stars":4}
的路由/ rateRateProduct
并填写产品5555(星号4)。在该示例中,它还填写谁进行评分。CommandHandler
(可能是通过依赖注入),然后将命令放在此处:h.Handle(c); 其中c是RateProduct命令。所以有3个选择:a)获取处理程序,b)获取队列,c)获取总线,并让它决定将命令发送到处理程序还是队列。
无论采用哪种方法,“经典存储库”的主要区别在于,您永远不会在控制器中调用存储库本身。 控制器不“知道如何管理实体”(经典存储库),但确实知道“如何管理对实体做事的意图”(命令处理程序)。
然后是命令处理程序-顾名思义-它“处理命令”来自意图发送的某处(html Web控制器,API控制器,命令行等),它是CommandHandler (属于写端),它决定如何处理该命令。
例如,CommandHandler可以使用存储库来获取产品,设置状态并保存(如示例中所示),但是它也可以写入事件日志,触发元素以更新读取侧,触发外部连接器或其他任何东西。
用户基于任务的用户界面将产品及其控制器定级为“放置或存储星标/定级系统”的“位置”。 假设您从头开始设计一个系统,并且Product类已经包含RateProduct()方法,如示例中所示。 好的。
但是...如果您那里有一个采用“旧”产品方法的旧系统,该怎么办。 在“模型”(即Business Mind)中,没有产品的“评级”。 相反,营销人员希望对现有产品进行“添加”评级,但是所有公司都同意这是“外部因素”。 您会使用产品存储库吗? 或者,也许是另一个帮助程序存储,这样您就不会“接触”已经在使用中并且已经过充分测试的产品和产品存储库了吗?
如果使用命令,则不介意编写控制器。 Web,API和CLI都只是将“命令”发送到命令处理程序(直接通过队列或通过将依次路由到处理程序或队列的命令总线)发送到命令处理程序,而他们忘记了。 然后,命令处理程序将在源代码的集中且较小的位置决定如何处理“ RateProductCommand”,这将处理方式与应用程序代码分离,从而获得了可维护性。
然后,处理程序将决定是否适合使用ProductRepository或其他任何方式来存储“产品的评分”。
所以,要回答:
CommandHandler =>与实体无关。 它处理“用户意图”(最终可能是更改实体;因此,命令处理程序很可能使用存储库)。
存储库=>某个实体的实际存储。
希望对您有所帮助。
哈维
如@xmontero所述,ProductsCommandHandler和ProductRepository仅具有“具有”关系。 ProductsCommandHandler充当ProductApi / Controller和ProductRepository之间的接口。 此实现有助于使命令与查询分开保持在一起。 在传统方法中,我们直接使用控制器中的存储库,将执行命令和查询保持在一起,因此之间不需要任何其他接口。
如果您将“命令”与“查询”分开,则已在应用程序中应用了CQRS设计模式。 它使您朝着获得本文中提到的CQRS的所有优势的方向发展。
最有用的评论
@martinmthomas实际上,命令处理程序不是存储库。 它使用一个存储库。
命令处理程序旨在“在适当的情况下处理实际命令”。 在示例中,
ProductsCommandHandler
类在其构造函数中收到IRepository<Product>
。假设用户将产品5555评分为4星。
{"product":"5555","stars":4}
的路由/ rateRateProduct
并填写产品5555(星号4)。在该示例中,它还填写谁进行评分。CommandHandler
(可能是通过依赖注入),然后将命令放在此处:h.Handle(c); 其中c是RateProduct命令。所以有3个选择:a)获取处理程序,b)获取队列,c)获取总线,并让它决定将命令发送到处理程序还是队列。
无论采用哪种方法,“经典存储库”的主要区别在于,您永远不会在控制器中调用存储库本身。 控制器不“知道如何管理实体”(经典存储库),但确实知道“如何管理对实体做事的意图”(命令处理程序)。
然后是命令处理程序-顾名思义-它“处理命令”来自意图发送的某处(html Web控制器,API控制器,命令行等),它是CommandHandler (属于写端),它决定如何处理该命令。
例如,CommandHandler可以使用存储库来获取产品,设置状态并保存(如示例中所示),但是它也可以写入事件日志,触发元素以更新读取侧,触发外部连接器或其他任何东西。
用户基于任务的用户界面将产品及其控制器定级为“放置或存储星标/定级系统”的“位置”。 假设您从头开始设计一个系统,并且Product类已经包含RateProduct()方法,如示例中所示。 好的。
但是...如果您那里有一个采用“旧”产品方法的旧系统,该怎么办。 在“模型”(即Business Mind)中,没有产品的“评级”。 相反,营销人员希望对现有产品进行“添加”评级,但是所有公司都同意这是“外部因素”。 您会使用产品存储库吗? 或者,也许是另一个帮助程序存储,这样您就不会“接触”已经在使用中并且已经过充分测试的产品和产品存储库了吗?
如果使用命令,则不介意编写控制器。 Web,API和CLI都只是将“命令”发送到命令处理程序(直接通过队列或通过将依次路由到处理程序或队列的命令总线)发送到命令处理程序,而他们忘记了。 然后,命令处理程序将在源代码的集中且较小的位置决定如何处理“ RateProductCommand”,这将处理方式与应用程序代码分离,从而获得了可维护性。
然后,处理程序将决定是否适合使用ProductRepository或其他任何方式来存储“产品的评分”。
所以,要回答:
CommandHandler =>与实体无关。 它处理“用户意图”(最终可能是更改实体;因此,命令处理程序很可能使用存储库)。
存储库=>某个实体的实际存储。
希望对您有所帮助。
哈维