开发者

POCOs != Domain Objects?

开发者 https://www.devze.com 2023-02-03 06:23 出处:网络
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.

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 thing开发者_高级运维s 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.)


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.


(None of these things are easy to do in EF. Maybe I need to use NHibernate or ADO.Net.)

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.


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.


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.


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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号