DDD - 实体不能直接访问 Repositories 的规则 [英] DDD - the rule that Entities can't access Repositories directly

查看:31
本文介绍了DDD - 实体不能直接访问 Repositories 的规则的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在领域驱动设计中,似乎有很多 实体不应访问的协议直接存储库.

In Domain Driven Design, there seems to be lots of agreement that Entities should not access Repositories directly.

这是否来自 Eric Evans 域驱动设计书,还是来自其他地方?

Did this come from Eric Evans Domain Driven Design book, or did it come from elsewhere?

对于其背后的推理,哪里有一些很好的解释?

Where are there some good explanations for the reasoning behind it?

澄清:我不是在谈论将数据访问从业务逻辑分离到一个单独的层的经典 OO 实践 - 我在谈论在 DDD 中实体不应该谈论的特定安排到数据访问层(即它们不应该保存对 Repository 对象的引用)

edit: To clarify: I'm not talking about the classic OO practice of separating data access off into a separate layer from the business logic - I'm talking about the specific arrangement whereby in DDD, Entities are not supposed to talk to the data access layer at all (i.e. they are not supposed to hold references to Repository objects)

更新:我给了 BacceSR 赏金,因为他的答案似乎最接近,但我对此仍然一无所知.这么重要的原则,网上应该有什么好文章吧?

update: I gave the bounty to BacceSR because his answer seemed closest, but I'm still pretty in the dark about this. If its such an important principle, there should be some good articles about it online somewhere, surely?

更新:2013 年 3 月,对这个问题的赞成意味着人们对此很感兴趣,即使有很多答案,我仍然认为如果人们对此有想法,还有更多空间.

update: March 2013, the upvotes on the question imply there's a lot of interest in this, and even though there's been lots of answers, I still think there's room for more if people have ideas about this.

推荐答案

这里有点混乱.存储库访问聚合根.聚合根是实体.这样做的原因是关注点分离和良好的分层.这对小型项目没有意义,但如果您在大型团队中,您想说:您通过产品存储库访问产品.产品是实体集合的聚合根,包括 ProductCatalog 对象.如果要更新 ProductCatalog,则必须通过 ProductRepository."

There's a bit of a confusion here. Repositories access aggregate roots. Aggregate roots are entities. The reason for this is separation of concerns and good layering. This doesn't make sense on small projects, but if you're on a large team you want to say, "You access a product through the Product Repository. Product is an aggregate root for a collection of entities, including the ProductCatalog object. If you want to update the ProductCatalog you must go through the ProductRepository."

通过这种方式,您可以非常非常清晰地分离业务逻辑和更新内容.你没有一个孩子独自一人写整个程序,把所有这些复杂的事情都写到产品目录中,当涉及到将它集成到上游项目时,你坐在那里看着它并意识到它一切都必须抛弃.这也意味着当人们加入团队、添加新功能时,他们知道去哪里以及如何构建程序.

In this way you have very, very clear separation on the business logic and where things get updated. You don't have some kid who is off by himself and writes this entire program that does all these complicated things to the product catalog and when it comes to integrate it to the upstream project, you're sitting there looking at it and realize it all has to be ditched. It also means when people join the team, add new features, they know where to go and how to structure the program.

等等!Repository 也指持久层,就像在 Repository Pattern 中一样.在更好的世界中,Eric Evans 的 Repository 和 Repository Pattern 将具有不同的名称,因为它们往往会重叠很多.要获得存储库模式,您需要与其他访问数据的方式(使用服务总线或事件模型系统)进行对比.通常当你达到这个级别时,Eric Evans 的 Repository 定义顺便说一句,你开始谈论有界上下文.每个有界上下文本质上都是它自己的应用程序.您可能有一个复杂的批准系统来将东西放入产品目录.在您的原始设计中,产品是核心部分,但在此有限上下文中,产品目录才是.您仍然可以通过服务总线访问产品信息和更新产品,但您必须意识到有界上下文之外的产品目录可能意味着完全不同的东西.

But wait! Repository also refers to the persistence layer, as in the Repository Pattern. In a better world an Eric Evans' Repository and the Repository Pattern would have separate names, because they tend to overlap quite a bit. To get the repository pattern you have contrast with other ways in which data is accessed, with a service bus or an event model system. Usually when you get to this level, the Eric Evans' Repository definition goes by the way side and you start talking about a bounded context. Each bounded context is essentially its own application. You might have a sophisticated approval system for getting things into the product catalog. In your original design the product was the center piece but in this bounded context the product catalog is. You still might access product information and update product via a service bus, but you must realize that a product catalog outside the bounded context might mean something completely different.

回到你最初的问题.如果您从实体内部访问存储库,则意味着该实体实际上不是业务实体,而可能是应该存在于服务层中的东西.这是因为实体是业务对象,应该尽可能像 DSL(领域特定语言)一样关注自己.该层只有业务信息.如果您正在对性能问题进行故障排除,您就会知道要查看其他地方,因为此处应该只包含业务信息.如果您突然遇到应用程序问题,那么扩展和维护应用程序变得非常困难,而这正是 DDD 的核心:制作可维护的软件.

Back to your original question. If you're accessing a repository from within an entity it means the entity is really not a business entity but probably something that should exist in a service layer. This is because entities are business object and should concern themselves with being as much like a DSL (domain specific language) as possible. Only have business information in this layer. If you're troubleshooting a performance issue, you'll know to look elsewhere since only business information should be here. If suddenly, you have application issues here, you're making it very hard to extend and maintain an application, which is really the heart of DDD: making maintainable software.

对评论 1 的回复:对,好问题.所以并不是所有验证都发生在域层.Sharp 有一个属性DomainSignature",可以满足您的需求.它具有持久性,但作为一个属性可以使域层保持干净.它确保您没有重复的实体,在您的示例中名称相同.

Response to Comment 1: Right, good question. So not all validation occurs in the domain layer. Sharp has an attribute "DomainSignature" that does what you want. It is persistence aware, but being an attribute keeps the domain layer clean. It ensures that you don't have a duplicate entity with, in your example the same name.

但让我们谈谈更复杂的验证规则.假设您是 Amazon.com.您是否曾经使用过期的信用卡订购过商品?我有,我没有更新卡并购买了一些东西.它接受订单,用户界面通知我一切都很好.大约 15 分钟后,我会收到一封电子邮件,说我的订单有问题,我的信用卡无效.这里发生的事情是,理想情况下,域层中有一些正则表达式验证.这是正确的信用卡号吗?如果是,则保留订单.但是,在应用程序任务层有额外的验证,其中查询外部服务以查看是否可以通过信用卡进行支付.如果没有,请不要实际发货,暂停订单并等待客户.这应该都发生在服务层中.

But let's talk about more complicated validation rules. Let's say you're Amazon.com. Have you ever ordered something with an expired credit card? I have, where I haven't updated the card and bought something. It accepts the order and the UI informs me that everything is peachy. About 15 minutes later, I'll get an e-mail saying there's a problem with my order, my credit card is invalid. What's happening here is that, ideally, there's some regex validation in the domain layer. Is this a correct credit card number? If yes, persist the order. However, there's additional validation at the application tasks layer, where an external service is queried to see if payment can be made on the credit card. If not, don't actually ship anything, suspend the order and wait for the customer. This should all take place in a service layer.

不要害怕在服务层创建验证对象, 可以访问存储库.把它放在域层之外.

Don't be afraid to create validation objects at the service layer that can access repositories. Just keep it out of the domain layer.

这篇关于DDD - 实体不能直接访问 Repositories 的规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆