POCO!= 域对象?
当我使用 ORM 完成我的第一个大型项目时,我开始意识到 ORM 将成为创建具有表现力和传达意图的领域对象的一大障碍。
也就是说,我知道我们不希望域对象仅仅是可公开访问的 getter 和 setter 的包。此外,我开始意识到仅仅拥有 IList
我的问题是:我在尝试以这种方式制作域对象方面是否走得太远了?这些问题是否应该只是其他应用程序组件的一部分?或者我应该有一个“真正的”域对象(具有表现力的东西)和一个由 ORM 水合的“哑” POCO 对象?
(编辑:系统吃了一堆我的尖括号。)
As I'm working through my first large project with an ORM, I've started to realize that the ORM will be a big impediment to creating domain objects that are expressive and that convey intent.
That is, I understand that we don't want domain objects to be merely bags of publicly-accessible getters and setters. In addition, I'm beginning to realize that simply having IList<T> all over the place doesn't convey intent and could invite abuse by developers using these objects. For example, maybe it's better to have ReadOnlyCollection<T> exposed. (I'm using .NET and Entity Framework, by the way.) And instead of an IList<MyDomainObject>, I've found myself wanting to expose a list of objects that are derived from MyDomainObject. (None of these things are easy to do in EF. Maybe I need to use NHibernate or ADO.Net.)
My questions are: Am I going too far in trying to craft domain objects in this way? Should these concerns just be part of some other application component? Or should I have a "real" domain object (that has the expressive stuff) and a "dumb" POCO object that is hydrated by the ORM?
(Edits: The system ate a bunch of my angle brackets.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我的观点是,您应该让 EF 做它该做的事情并创建免费的 POCO。您也可以将它们称为 DTO - 它们的作用是充当内存与持久性之间的桥梁。就您的“域”而言,我从未相信您的数据库架构反映了一致的域模型。因此,我总是在持久性(或存储库)层之上创建一个域层来代表业务域,从而将持久性的香肠工厂排除在外。该域层可以根据需要混搭您的 DTO,以创建一个面向开发人员的有意义的模型。使用工厂模式从 DTO 创建域对象,反之亦然 - 将 DTO 保留在客户端代码之外,以便您可以将架构更改与使用者隔离。
这是更多的工作,更多的映射代码等,但这是值得的 - EF 已经减少了你的代码,我认为你实际上应该花时间来编码域逻辑和表示,这就是让你比代码生成工具更好的原因: )
祝你好运。
My view is that you let the EF do it's thing and create the freebie POCOs. You could also call them DTOs - their role is to be the bridge from memory to persistence and back. As far as your "domain" goes, I've never bought into the idea that your DB schema reflects a coherent domain model. As a result, I've always created a Domain layer on top of the Persistence (or repository) layer which represents the business domain, keeping the sausage factory that is Persistence out of the mix. This Domain layer can mash up your DTOs as required to make a developer-facing model that makes sense. Use a factory pattern to create Domain objects from the DTOs and vice versa - keep the DTOs out of the client code such that you can isolate schema changes from consumers.
It's more work, more mapping code etc but it's worth it - EF already cuts your code down, and I would argue you should in fact be taking time to code the domain logic and representation, it's what makes you better than a code generation tool :)
Good luck.
宾果游戏。 EF 不支持与 NHibernate 或自定义构建的解决方案相同级别的域和持久性基础设施之间的独立性。
至于公开的类型,我坚持使用 IEnumerable 并在父级上使用 Add 和 Remove 方法,通常......有时是自定义集合,但从不使用 IList。
Bingo. EF doesn't support the same level of independence between your domain and your persistence infrastructure as NHibernate or a custom built solution can.
As for the types exposed, I stick with IEnumerable and use Add and Remove methods on the parent, usually.. sometimes custom collections, but never IList.
我尝试在几个项目中使用 POCO 作为域对象,坦率地说,它只适用于简单/小型项目。
我喜欢 ORM 并且不会停止使用它们。但我总是在 orm/repository 层之上构建一个领域层。我创建了在我的应用程序中使用的特定域对象。我使用像 automapper 这样的映射框架来将域对象与数据对象相互转换。
我对您的建议是,如果您正在使用实体框架,请停止使用 POCO,并让 EF 为您生成数据对象。然后创建域对象,并让 automapper 处理域层中的映射。
这需要更多的工作,但更灵活且更容易使用。
I've tried to use POCOs in several projects as domain objects and frankly it only work for simple/small projects.
I love ORMs and will not stop to use them. But I always build a domain layer on top of the orm/repository layer. And I create specific domain objects which is used in my application. I use a mapping framework like automapper to convert domain objects to/from data objects.
My recommendation to you is to stop using POCOs if you are using entity framework and let EF generate the data objects for you. Then create domain objects instead and let automapper handle the mappings in your domain layer instead.
It's a bit more work but it's more flexible and easier to work with.
这是一个非常好的问题——也是我在尝试对领域对象使用 ORM 时逐渐意识到的问题。我的域对象公开 IEnumerable 类型的公共属性,该属性返回 ReadOnlyCollection,因此添加到集合的唯一方法是在父级上调用自定义 Add 方法。
在我看来,不,你不会走得太远,以这种方式制作你的对象。
我完全赞成尝试最大限度地封装你的对象,保持字段私有并提供原子的、显式的公共方法显示意图,并确保对象只能以有效状态存在。如果这意味着使用原始 ADO.NET,那就这样吧。对我来说,选择 DAL 技术不应影响对域对象进行严格的设计。
然而,我讨厌编写样板 DAL 代码,并且现在用存储过程编写原始 ADO.NET 会让我头疼。我逐渐意识到,如果您使用事件源作为域对象的持久性机制,那么为封装的域对象编写 DAL 就会变得非常非常变得更加容易。您所需要的只是一个事件表,它将所有事件存储为序列化数据。由于域对象本身不会持久化,因此存储库无权访问域对象上的 List 属性并不重要。然后,您的工作单元“引发”查询组件可以处理的这些事件,这将使用简单的 DTO 和 ORM 填充/更新您需要的任何表。
这是事件溯源的示例
CQRS 和事件溯源实际上旨在提供高可扩展性,并且根据定义包括许多基于“最终一致”范例的异步操作。然而,即使在处理不需要这种级别的可扩展性的项目时,我发现以同步方式遵循这些模式提供了一种机制来保持我的域对象完全封装,同时不必编写单行手工制作的 DAL 代码,节省大量时间,并为所采取的每项操作提供完整的审计跟踪(事件),并且免费提供。如果您的系统需要通过消息传递与第三方系统进行通信,这也是一个非常宝贵的工具。
This is a really good question - and something that I've come to realise when trying to use an ORM for domain objects. My domain objects expose public properties of type IEnumerable which return ReadOnlyCollection so the only way to add to the collection is to call a custom Add method on the parent.
In my opinion, no, you are not going too far to craft your objects this way.
I fully condone trying to encapsulate your objects to the maximum, keeping fields private and providing public methods that are atomic, explicitly show intent, and ensuring that objects can only exist in a valid state. If this means using raw ADO.NET, then so be it. To me, keeping the domain objects to a strict design shouldn't be compromised by the choice of DAL technology.
However, I HATE writing boiler plate DAL code and writing raw ADO.NET with sprocs would do my head in these days. What I've come to realise is that writing DAL for encapsulated domain objects becomes MUCH MUCH MUCH easier if you use Event Sourcing as the persistence mechanism for your domain objects. All you need is an Event table which stores all your events as serialised data. Because the domain objects themselves aren't persisted, it doesn't matter that the repositories don't have access to a List property on a domain object. Your unit of work then 'raises' these events which a query component can handle, which will populate/update any tables you need to using simple DTO's and an ORM.
Here's an example of event sourcing
CQRS & Event sourcing actually is designed to provide high scalability and by definition includes a lot asynchronous operations based on the 'eventually consistent' paradigm. However, even when working on projects that don't require this level of scalability, I find following the these patterns in a synchronous manner provides a mechanism to keep my domain objects completely encapsulated, whilst not having to write single line of hand crafted DAL code, saving a MASSIVE amount of time, and providing a complete audit trail (the events) for every action ever taken, thrown in for free. This is also an invaluable tool if your system needs to communicate to 3rd party systems via messaging.
没有什么说 POCO 不能包含您自己的复杂对象。 POCO 之所以成为 POCO 的原因在于它与数据状态没有链接,而不是它只能包含列表作为对象。
There's nothing that says a POCO can't contain your own, complex objects. What makes a POCO a POCO is that it has no linkage to the Data state, not that it can only contain Lists as objects.