Your ORM “Model” is not your Domain Model

So what I’ve started to do with new projects is to treat the ORM as a data-specific layer, similar to how you would treat data consumed from a web service.  There’s a separate layer dealing with the mapping logic, and you never expose the underlying data model.  It creates some extra work, but makes the rest of the application easier to write and more reliable.  It also means that if you decide to use stored procedures or some other custom data access logic code, it’s completely abstracted.

For anything vaguely complex, I find the latter of the following patterns desirable.

ORM-centered Pattern:

(ORM + business logic)  -> (UI/ORM mapping) -> UI

ORM-ignorant pattern:

ORM model -> (ORM/Domain model mapping)  -> Domain model + business logic  -> (UI/Domain model mapping) -> UI

What do you think?

Page 2 of 2 | Previous page

  1. willem:

    Nice food for thought. I agree from a purist point of view.

    When looking at Entity Framework though, your model is mostly independent from your storage layer (apart from the need to query, at times, by telling the data store what to eager load).

    So I don’t feel *too* bad treating my Entity Framework model as my Domain Model.

    I do have a problem however with treating a Linq2Sql model as a domain model though, that’s going too far. i.e. mixing active record with domain model. Eugh.

  2. Samuel Goldenbaum:

    Few points to consider, your ORM is just an infrastructure concern. Our domain model, in pure DDD, should really be persistence agnostic. Your domain shouldn’t really care if you are saving to relational db, file system, xml or storing in a in-memory collection.

    That’s where patterns like Repository pattern and Unit of Work come into play. There shouldn’t really be any talking to the ORM in your model.

    It is not really an “ORM pattern” though.

    Problem sometimes with the designers in tools like EF, is that devs create the database and the drag around some tables and classes and the assume the have a “domain”. Clearly that not the case and always encourage design to start in the domain model first and then map that to a schema when done.

  3. willem:

    Sam, sounds like you are saying exactly what John is suggesting? Map from ORM model to your actual domain model, so keep them completely separate?

  4. Samuel Goldenbaum:

    Yip, they are not one and the same. I would always start by creating my domain model first as opposed to the DB schema first. Makes a big difference when being able to talk about the actual business domain as opposed to tables. We don’t care about tables we care about entities and they may be stored in a bunch of different places from relational db to document db etc.

    (Beware anti-DDD-purist comments below)
    Having said that – if you know you are always going to use a relational db for persistence, you can get great benefits from letting your ORM leak into your model as there are often specific ORM provider features that are very powerful and useful that would be lost when developing against a set of interfaces exposing lowest common denominator like IRepository.

  5. avesse:

    @Willem: I agree that EF/NH makes your model cleaner in that you don’t use generated code. The problem is (as mentioned in the post) that e.g. at Controller level in an MVC app you still have access to the related entities as properties of the main entity. This applies to POCOs as well as Linq2Sql-generated classes.

    And if it’s there, it can be used. If the entity was loaded from cache, it’ll break (because the related entities were not loaded pre-caching, and it’s not bound to the DataContext). If it wasn’t loaded from cache, it’ll cause the select n+1 issue. This is the main reason I’m going for the additional layer approach.

  6. Samuel Goldenbaum:

    @avesse I actually mark almost all my associations and collections as not-lazy to ensure that each method that returns entities will eager-load only what is needed for that request.

    This ensures you model is not being called from your view, MVC pattern after all, and avoids issues like select n+1. Normally I would transform the entities into a simple DTO and cache the DTO, not the entities.

    I normally profile every call to see exactly what is being returned and sql generated. Lazy loading is great in desktop apps or when the db is close to the app, but don’t feel it works in web apps.

  7. KarolMasters:

    I see your website needs some unique content.
    Writing manually is time consuming, but there is
    solution for this. Just search for: Masquro’s strategies