DDD 中的数据访问?
阅读 Evan 和 Nilsson 的书后,我仍然不确定如何在域驱动项目中管理数据访问。 CRUD 方法应该是存储库的一部分,即 OrderRepository.GetOrdersByCustomer(customer),还是应该是实体的一部分:Customer.GetOrders()。 后一种方法看起来更面向对象,但它将在多个对象之间分配单个实体类型的数据访问,即 Customer.GetOrders()、Invoice.GetOrders()、ShipmentBatch.GetOrders() 等。 插入和更新怎么样?
After reading Evan's and Nilsson's books I am still not sure how to manage Data access in a domain driven project. Should the CRUD methods be part of the repositories, i.e. OrderRepository.GetOrdersByCustomer(customer) or should they be part of the entities: Customer.GetOrders(). The latter approach seems more OO, but it will distribute Data Access for a single entity type among multiple objects, i.e. Customer.GetOrders(), Invoice.GetOrders(), ShipmentBatch.GetOrders() ,etc. What about Inserting and updating?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我已经完成了你所说的两种方法,我现在首选的方法是持久无知(或 PONO - 普通 Ole'.Net 对象)方法,其中你的域类只担心是域类。 他们不知道它们是如何被持久化的,甚至不知道它们是否被持久化。 当然,有时你必须务实一点,并允许诸如 Id 之类的东西(但即使这样,我也只是使用具有 Id 的图层超级类型,这样我就可以有一个点,其中像默认值这样的东西存在
)这样做的原因是我努力遵循单一职责原则。 通过遵循这个原则,我发现我的代码更易于测试和维护。 当需要时进行更改也更容易,因为我只需考虑一件事。
需要注意的一件事是存储库可能遭受的方法膨胀。 GetOrderbyCustomer.. GetAllOrders.. GetOrders30DaysOld.. 等等。解决此问题的一个好方法是查看查询对象模式。 然后您的存储库只需接受一个查询对象即可执行。
我还强烈建议研究 NHibernate 之类的东西。 它包含许多使存储库如此有用的概念(身份映射、缓存、查询对象......)
I've done it both ways you are talking about, My preferred approach now is the persistent ignorant (or PONO -- Plain Ole' .Net Object) method where your domain classes are only worried about being domain classes. They do not know anything about how they are persisted or even if they are persisted. Of course you have to be pragmatic about this at times and allow for things such as an Id (but even then I just use a layer super type which has the Id so I can have a single point where things like default value live)
The main reason for this is that I strive to follow the principle of Single Responsibility. By following this principle I've found my code much more testable and maintainable. It's also much easier to make changes when they are needed since I only have one thing to think about.
One thing to be watchful of is the method bloat that repositories can suffer from. GetOrderbyCustomer.. GetAllOrders.. GetOrders30DaysOld.. etc etc. One good solution to this problem is to look at the Query Object pattern. And then your repositories can just take in a query object to execute.
I'd also strongly recommend looking into something like NHibernate. It includes a lot of the concepts that make Repositories so useful (Identity Map, Cache, Query objects..)
CRUD-ish 方法应该是存储库的一部分...ish。 但我认为你应该问为什么你有一堆 CRUD 方法。 他们真正做什么? 它们的真正用途是什么? 如果您实际上指出了应用程序使用的数据访问模式,我认为这会使存储库变得更加有用,并且当您的域发生某些类型的更改时,您不必进行鸟枪手术。
“保存”类型的方法也应该是存储库的一部分。
如果您有聚合根,这可以防止存储库爆炸或逻辑分散:您没有 4 x # 的实体数据访问模式,只有您在聚合根上实际使用的模式。
那是我的 0.02 美元。
CRUD-ish methods should be part of the Repository...ish. But I think you should ask why you have a bunch of CRUD methods. What do they really do? What are they really for? If you actually call out the data access patterns your application uses I think it makes the repository a lot more useful and keeps you from having to do shotgun surgery when certain types of changes happen to your domain.
"Save" type methods should also be part of the repository.
If you have aggregate roots, this keeps you from having a Repository explosion, or having logic spread out all over: You don't have 4 x # of entities data access patterns, just the ones you actually use on the aggregate roots.
That's my $.02.
DDD 通常更喜欢存储库模式而不是您使用 Customer.Save 暗示的活动记录模式。
Active Record 模型的一个缺点是它几乎假定一个单一的持久性模型,除非有一些特别侵入性的代码(在大多数语言中)。
存储库接口是在领域层定义的,但不知道你的数据是否存储在数据库中。 例如,使用存储库模式,我可以创建一个 InMemoryRepository,以便可以单独测试域逻辑,并在应用程序中使用依赖项注入来让服务层实例化 SqlRepository。
对于许多人来说,拥有一个仅用于测试的特殊存储库听起来很愚蠢,但如果您使用存储库模型,您可能会发现您的特定应用程序实际上并不需要数据库;您可以使用存储库模型。 有时一个简单的 FileRepository 就可以解决问题。 在您知道自己需要数据库之前就将自己与数据库结合起来可能会受到限制。 即使数据库是必要的,针对 InMemoryRepository 运行测试也会快得多。
如果您没有太多领域逻辑方面的知识,那么您可能不需要 DDD。 ActiveRecord 非常适合解决很多问题,特别是当您主要有数据和少量逻辑时。
DDD usually prefers the repository pattern over the active record pattern you hint at with Customer.Save.
One downside in the Active Record model is that it pretty much presumes a single persistence model, barring some particularly intrusive code (in most languages).
The repository interface is defined in the domain layer, but doesn't know whether your data is stored in a database or not. With the repository pattern, I can create an InMemoryRepository so that I can test domain logic in isolation, and use dependency injection in the application to have the service layer instantiate a SqlRepository, for example.
To many people, having a special repository just for testing sounds goofy, but if you use the repository model, you may find that you don't really need a database for your particular application; sometimes a simple FileRepository will do the trick. Wedding to yourself to a database before you know you need it is potentially limiting. Even if a database is necessary, it's a lot faster to run tests against an InMemoryRepository.
If you don't have much in the way of domain logic, you probably don't need DDD. ActiveRecord is quite suitable for a lot of problems, especially if you have mostly data and just a little bit of logic.
让我们退后一步。 埃文斯建议存储库返回聚合根而不仅仅是实体。 因此,假设您的客户是包含订单的聚合根,那么当您从其存储库中获取客户时,订单也会随之而来。 您可以通过导航从“客户”到“订单”的关系来访问订单。
因此,为了回答您的问题,CRUD 操作存在于聚合根存储库上。
Let's step back for a second. Evans recommends that repositories return aggregate roots and not just entities. So assuming that your Customer is an aggregate root that includes Orders, then when you fetched the customer from its repository, the orders came along with it. You would access the orders by navigating the relationship from Customer to Orders.
So to answer your question, CRUD operations are present on aggregate root repositories.
即使在 DDD 中,我也会将数据访问类和例程与实体分开。
原因是,
我不是专家,只是我的意见。
Even in a DDD, I would keep Data Access classes and routines separate from Entities.
Reasons are,
I am no expert, just my opinion.
Nilsson 的应用 DDD&P 的烦人之处在于,他总是以“我不会在现实世界的应用程序中这样做,但是......”开始,然后他的例子如下。 回到主题:我认为 OrderRepository.GetOrdersByCustomer(customer) 是可行的方法,但 ALT.Net 邮件列表上也有讨论 (http://tech.groups.yahoo.com/group/altdotnet/)有关 DDD。
The annoying thing with Nilsson's Applying DDD&P is that he always starts with "I wouldn't do that in a real-world-application but..." and then his example follows. Back to the topic: I think OrderRepository.GetOrdersByCustomer(customer) is the way to go, but there is also a discussion on the ALT.Net Mailing list (http://tech.groups.yahoo.com/group/altdotnet/) about DDD.