fal*_*con 2 domain-driven-design microservices
我看过很多关于这个话题的讨论,但我无法得到令人信服的答案.一般建议不要在域对象中包含存储库.聚合根怎么样?赋予根操纵组合对象的责任是不是正确的?例如,我有一个处理发票的微服务.发票是具有不同产品的聚合根.此服务无需提供有关各个产品的详细信息.我有2个表,一个用于存储发票详细信息,另一个用于存储这些发票的产品.我有两个与表对应的存储库.我在发票域对象中注入了产品存储库.这样做是不对的?
是的,我认为这是错误的.
域应该与实际业务模型匹配,并且不应该关心数据的持久性.即使内部数据存储在多个表中,也不会以任何方式影响域对象.
当您加载聚合根时,您应该一次加载相关实体.例如,Include如果您使用的是.NET ,则可以使用Entity Framework中的关键字轻松实现.通过加载所有数据,您可以确保在任何给定时间都拥有业务实体的完整表示,并且您不必再查询数据库.
相关实体中的任何更改都应与一个原子操作(通常使用事务)中的聚合根一起保留.
根据您的问题中的DDD原则,我看到了一些错误.让我试着澄清一些概念来帮助你.
首先,您提到您有一个Aggregate Root,它是Invoice,然后是两个不同的存储库.拥有聚合根意味着聚合所包含的实体的任何更改都应通过聚合根执行.为什么?那是因为您需要满足适用于这些实体关系的某些业务规则(不变量).例如,给定下一个业务规则:
必须始终在拍卖结束前放置获胜的拍卖出价.如果在拍卖结束后放置中标,则域处于无效状态,因为已经破坏了不变量并且模型未能正确应用域规则.
这里有一个由Auction和Bids组成的聚合,其中Auction是Aggregate Root.
如果你有BidsRepository,你可以很容易地做到:
var newBid = new Bid(money);
BidsRepository->save(newBid);
Run Code Online (Sandbox Code Playgroud)
并且您在未传递已定义的业务规则的情况下保存了出价.但是,将存储库仅用于聚合根,您将强制执行您的设计,因为您需要执行以下操作:
var newBid = new Bid(money);
auction.placeBid(newBid);
auctionRepository.save(auction);
Run Code Online (Sandbox Code Playgroud)
因此,您可以检查方法中的不变量placeBid,如果他们想要设置新的出价,则无人可以跳过它.之后,您可以将信息保存到任意数量的表中,这是一个实现细节.
其次,你说如果将存储库注入Domain类是错误的.这里有一个快速解释:
存储库应该依赖于它返回的对象,而不是相反.这样做的原因是你的"域对象"(稍后会更多)可以存在(并且应该是可测试的)而不加载或保存(即,依赖于存储库).
基本上你的设计说,为了有发票,你需要提供一个MySQL/Mongo/XXX实例连接,这是一个基础设施细节.您的域名不应该知道它是如何持久化的.您的域名了解拍卖和出价情景中的行为.
这些概念只是帮助您创建更易于维护的代码,并帮助您应用SRP(单一责任原则)等最佳实践.