Don't Use ORM Entities To Model The Domain

By Mike on 20 April 2012

Initially I wanted to include this in the Entities and Value Objects explained post, but I think this matter deserves its own post.

When you model the Domain, for your own good FORGET about databases, ORMs etc! Because the design of the model must be dictated by the domain. If you put an id in a domain object, then it better have its use within the Domain. Keeping that code clean, will make the code much easier to understand and to modify.

 If it happens that a type will be persisted with an Id because that's what the ORM wants, you should NOT change the Domain model. Put the id in the Persistence Model and leave the Domain Model as it was.  If you change the Domain object just for the sake of another layer, in fact just for the sake of a different BC, that model becomes inconsistent within its BC. Yes an Id doesn't change much or making a property virtual (because that's what the ORM requires), but it tells to a future maintainer that it's ok to subclass the type and override a property, because well... that's why is virtual in the first place, right?

 What do you do, you put in the comments : "this is in fact a Value Object but we need the Id for NHibernate, DO NOT change!" or "This property is virtual because EF requires it"? Come on, you want to do DDD and have a robust code, or you just want to throw buzzwords around, while continuing to do the things 'the old way' ? If that app, switches to use Redis or MongoDb, an ORM becomes useless, but hey, your 'domain' objects are tied to the ORM requirements so you just keep them. Of course, now any (new) developer will the comments then asks himself: "Huh, we don't use NHibernate... Wtf is this?!"

 The objects , entities that you define for ORM use are for ORM use ONLY. Those objects must evolve according to the storage needs. If you used them for the domain, you'll have an abomination, the entity will serve two masters and none of them well. Any time you'll change one because one master needs it, you have to account for the effects from the other master. You know not to mix the UI with calling the db, why do you think is ok to use a Persistence implementation detail as the base for your Domain?

 "It's about DRY" you might say. I like DRY, but here you just invoke it as an excuse for mixing responsibilities.  You don't have identical code in two layers, they might 'share' 90% but they are different and those differences matter. Those will give you the headaches. Even if at one point they are 100% identical: each code was written with DIFFERENT INTENTION in mind. It just happened to be identical. If you keep them separate, then one can change without messing the other.

 What about maintainability, you ask? This is maintainable code. The code you can understand in a second and you can modify in a minute. If you are worried about writing the same properties, there is an old technique which usually is abused but here it's very appropriate: it's called copy/paste and it will solve this specific problem in a second.

 What's more difficult: to copy/paste in 2 seconds every time it makes sense or to keep one code base and then praying that modifying something didn't break the functionality in another layer?

 That's why I'm a firm supporter of the separation of the Domain Model from the Persistence Model when using an ORM. The ORM docs might say that you model the domain entities, but in fact you'll be always modelling the Persistence Model because this the ORM's purpose: to handle the persistence of objects in a relational database. It's not its purpose to model domain behavior.

 Model the Domain entities for the Domain needs, model the Persistence entities for the Persistence needs. Don't forget that an ORM is ALWAYS an implementation detail of the Persistence.

Comments (10) -

Marius George
Marius George
25 November 2013 #

Hi Mike,

I agree with 99% of what you are saying in the various blogs.

In this this article...

"If it happens that a type will be persisted with an Id because that's what the ORM wants, you should NOT change the Domain model. Put the id in the Persistence Model and leave the Domain Model as it was."

The question then is, if my domain entity has no natural identifier, how would I bridge the gap back to the database? If the database entity has an auto int ID, and this is not brought into my domain entity, then how do I know what record in the database this eventually maps to when the entity is persisted back to the database?

(Assume I'm using UI <-> Domain Model <--> Repo using ORM <--> Database)

Reply

Admin
Admin
26 November 2013 #

An entity without a natural identifier isn't much of an entity, is it?  Smile Even we as citizens of a country are identified by a personal identification number which must be unique, instead of simply our names.

By default, all my entities have a Guid Id just because I want to uniquely identify the entity, but not because the persistence wants it.

Many times the persistence model also has an auto generated id too, which never leaves the Repository and it's used only inside the Persistence.

Things gen funny when you have a natural id that can be unique. I'd still use a Guid Id because that natural id may change in time (think invoices and a new way to generate invoice id because a new law forces this).

In my post I talk about Value Objects because they don't have an identity while their persistence models can have. The entities always have some kind of id, you only need to decide what it will be.

Reply

Alex
Alex
6 December 2013 #

@Marius George
Why just not use numerical ID as an identifier in your domain? What's so wrong about this? Smile

( Btw I recently started to like Domain Model - Repo with ORM - DB chain, makes obvious advantages of ORM usage available, yet allows for flexibility when creating domain models . Smile )

Reply

Matt Goodwin
Matt Goodwin
3 December 2013 #

When using an ORM, how would you fetch records back from the persistence layer and them map these to your Domain? Do you have a particular mapper class that does this or is this just done directly in your QueryHandler?

Reply

Admin
Admin
3 December 2013 #

I'd use a mapper. However I'd also use CQRS and for domain purposes the entities would be persisted serialized while the read (query) model would be in an easy to query form.

Reply

Matt Goodwin
Matt Goodwin
3 December 2013 #

When you say 'serialized', do you mean serialized in cache ready for the query and not in the persistence layer?

Reply

Admin
Admin
4 December 2013 #

I meant serialized in the database. For domain purposes most of the time you need only GetById functionality, so it's easier to use a key-value approach (regardless of db type) for storing any entity. The relational schema is used only for the read model.

Basically, after the domain data is persisted, the read model is updated(created) and this is where you can go wild with the ORM, db normalization etc. And you can have more than one read model too, it all depends on the app needs, there isn't a generic recipe for this.

Reply

Matt Goodwin
Matt Goodwin
4 December 2013 #

Wont serializing the domain model in the database cause you headache if you wanted to change your domain model (say if the requirements change after the initial build)?

Reply

Admin
Admin
4 December 2013 #

Well that's the reason I prefer using the Memento pattern, so I'm actually storing the memento and not the entity itself. However, memento means some duplicated boring code. Personally, I think it's worth the 'trouble' (well, minutes) but a lot of people don't share this opinion.

In the end, it's up to you to find what approach best suits your style and the application. there's never a best method always for everyone.

Reply

4past12
4past12
18 January 2014 #

I couldn't agree more with you. We've all been reading the EF documentation from MS so long (where they even state "DbContext is a representation of a Repository and Unit of Work"). EF represents an ORM, and a properly implemented Repository interfaces between the ORM/Data Mapper and the Domain Model objects. Further more, Domain Model objects contain not just data, but also operations those objects can perform. Since EF "domain model" objects are POCOs, a critical piece of Domain Model objects is lost--not to mention that your Domain Model need not necessarily reflect the schema of your database. The database is for persistence of data only. Your domain model may require quite a  different "schema" or topology than your persistence layer in order to more accurately carry out the business requirements and functionality of the application and, therefore, is a completely separate concern from the persistence mechanism and implementation.

And what's up with the dumb CAPTCHA trivia questions that I could care less to know the answer to?? I had to "research" the answer just to post this.....

Reply

Add comment

biuquote
Loading