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

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

问题描述

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

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?

edit:澄清一下:我不是在谈论将数据访问从业务逻辑分离到单独的层中的经典OO做法-而是在DDD中,实体不应该谈论的具体安排完全到数据访问层(即,它们不应保存对存储库对象的引用)

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.

推荐答案

这里有些混乱.存储库访问聚合根.聚合根是实体.这样做的原因是关注点分离和良好的分层.在小型项目中这没有意义,但是如果您在大型团队中,您会说:您可以通过Product Repository访问产品.Product是实体集合(包括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.

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

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的回复:对,很好的问题.因此,并非 all 验证在域层中进行.夏普有一个"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.您是否曾经使用过期的信用卡订购过商品?我有,但我还没有更新卡和买东西.它接受订单,并且UI通知我所有东西都是桃红色的.大约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-实体不能直接访问存储库的规则的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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