存储库模式问题
我正在构建一个 ASP.NET MVC 应用程序,并使用存储库来存储和检索视图对象。我的问题是,各个存储库的实现可以互相调用吗? IE 可以通过 ICustomerRepository
实现调用 IAddressRepository
的实现,还是应该自行处理对地址数据源的更新?
编辑:
谢谢大家,客户/地址示例不是真实的。实际问题涉及三个聚合,它们更新第四个聚合以响应各自状态的变化。在这种情况下,引入依赖项与违反“不重复自己”原则之间似乎存在冲突。
I'm building an ASP.NET MVC app and I'm using a repository to store and retrieve view objects. My question is, is it okay for the implementation of the various repositories to call each other? I.E. can the ICustomerRepository
implementation call an implementation of IAddressRepository
, or should it handle its own updates to the address data source?
EDIT:
Thanks everyone, the the Customer/Address example isn't real. The actual problem involves three aggregates which update a fourth aggregate in response to changes in their respective states. I in this case it seems a conflict between introducing dependencies vs violating the don't repeat yourself principle.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您应该为每个聚合根都有一个存储库。
我不了解您的域模型,但拥有 IAddressRepository 对我来说并不自然。除非“地址”是您域中的聚合根。
事实上,在大多数情况下,“地址”甚至不是一个实体,而是一个值对象。也就是说,在大多数情况下,“地址”的身份由其值(其所有属性的值)确定;它没有单独的“Id”(键)字段。
因此,在这种情况下,CustomerRepository 应该负责存储地址,因为地址是客户聚合根的一部分。
编辑(好吧,你的情况只是一个例子):
但是,如果您在其他情况下需要存储库中的另一个存储库,那么我认为最好从中删除该功能存储库,并将其放在单独的类(Service)中。
我的意思是:我认为,如果存储库 A 内有某些功能依赖于另一个存储库 B,那么这种功能不属于存储库 A 内。
相反,编写另一个类(在 DDD 中称为服务),在其中实现此功能。
无论如何,我认为存储库不应该真正相互调用。但是,如果您不想编写服务,并且确实希望将该逻辑保留在存储库本身内,则可以将另一个存储库作为该特定方法中的参数传递。
我希望我说得清楚一点。 :P
You should have a repository for each aggregate root.
I have no knowledge of your domain-model, but it doesn't feel natural for me to have an IAddressRepository. Unless 'Address' is an aggregate root in your domain.
In fact, in most circumstances, 'Address' is not even an entity, but a value object. That is, in most cases the identity of an 'Address' is determined by its value (the value of all its properties); it does not have a separate 'Id' (key) field.
So, when this is the case, the CustomerRepository should be responsible for storing the Address, as the Address is a part of the Customer aggregate-root.
Edit (ok so your situation was just an example):
But, if you have other situations where you would need another repository in a repository, then I think that it is better to remove that functionality out of that repository, and put it in a separate class (Service).
I mean: I think that, if you have some functionality inside a repository A, that relies on another repository B, then this kind of functionality doesn't belong inside repository A.
Instead, write another class (which is called a Service in DDD), in where you implement this functionality.
Anyway, I do not think that repositories should really call each other. If you do not want to write a Service however, and if you really want to keep that logic inside the repository itself, then pass the other repository as an argument in that specific method.
I hope I made myself a bit clear. :P
他们真的不应该互相打电话。存储库是您想要在域上执行的(或多或少)原子操作的抽象。他们的依赖性越少越好。实际上,存储库的任何使用者都应该期望能够将存储库类指向数据库,并让它执行必要的域操作,而无需进行大量配置。
它们还应该代表您领域中的“聚合”,即许多功能将基于的关键焦点。我想知道为什么你会有一个单独的地址信息存储库?这不应该是您的客户存储库的一部分吗?
They really shouldn't call each other. A Repository is an abstraction of the (more or less) atomic operations that you want to perform on your domain. The less dependency they have, the better. Realistically, any consumer of a repository should expect to be able to point the repository class at a database and have it perform the necessary domain operations without a lot of configuration.
They should also represent "aggregates" in your domain - i.e. key focal points that a lot of functionality will be based around. I'm wondering why you would have a separate address information repository? Shouldn't that be part of your customer repository?
这取决于存储库的类型(或者至少取决于后果),但一般来说,如果您有数据存储库相互调用,您将遇到诸如循环之类的问题(存储库 A -> 需要 B -> 需要C - 哎呀,需要 A)或递归数据加载(A - > 需要 B 和 C - > C - 需要 D,E - > .... - > ..令人作呕)。测试也变得更加困难。
例如,您需要加载地址存储库才能正确运行客户存储库,因为客户存储库会调用地址存储库。如果您需要测试客户存储库,则需要对地址进行数据库加载或以某种方式模拟它们,最终您将无法在不加载全部地址的情况下加载和测试任何单个系统存储库。
拥有这些依赖关系也有点阴险,因为它们通常不清楚 - 通常您将存储库作为数据保存抽象来处理 - 如果您必须意识到它们如何相互依赖,您就无法使用它们作为一个抽象,但每当你想使用它们时都必须管理加载过程。
This depends on the type of repository (or at least the consequences do) but in general if you have data repositories calling each other you're going to run into problems with things like cyclical (repo A -> requires B -> requires C -. oops, requires A) or recursive data loads (A-> requires B & C -> C-requires D, E -> .... ->..ad nauseum). Testing also becomes more difficult.
For example, you need to load your address repository to properly run your customer repository, because the customer repository calls the address repo. If you need to test the customer repo, you'll need to do a db load of the addresses or mock them in some way, and ultimately you won't be able to load and test any single system repository without loading them all.
Having those dependencies is also kind of insidious because they're often not clear - usually you're dealing with a repository as a data-holding abstraction - if you have to be conscious of how they depend on each other you can't use them as an abstraction, but have to manage the load process whenever you want to use them.