I don't believe in ORM object as your domain model

Posted by Sarah on June 02, 2009 · 4 mins read

I have been on a few projects now where we have used ORM libraries to help store our data (eg ActiveRecord for Rails, Hibernate (and it’s variants), Castle’s ActiveRecord for .Net). On these projects, we have used the domain models and the ORM models are the same.

The problem we faced with doing so is the same problems I think most people face : eventually, your domain wants to take your model in one direction, and your relational database wants to take it in another. Personally, I really like Domain Driven Design - I like my objects to be reflective of the domain - and I don’t really care about how the database stores them, or indexes or stuff like that (I seem to remember something about BNF back in uni), so I am more inclined to let my model move towards the domain; but I do understand that there are consequences in doing so when looking at how my data is accessed.

I have now come to the belief that there is value in having my domain models but equally having ORM models. More so, I have decided that (despite the perceived increase in classes) there is a true distinction between the two and should be implemented as two separate classes. You can see from my examples what I am talking about, but basically my domain model knows nothing about the ORM model and anyone (apart from the necessary repository) knows about it either. The ORM model is used by the repository of concern as a helpful tool for it to store to the database; it could equally be done using SQL.

# The Domain model - yes there is more to it than that
class RegistrationForm

  def initialize(key)
    @key = key
    @name = ""
    @email = ""
  end
  ...
end
# The repository to find/save a registration
class RegistrationRepository

  def find(key)
    registration = find_registration(key)
    form = RegistrationForm.new
    return form unless registration
    update_form(form, registration)
  end

  def save(form)
    registration = find_registration(form[:key])
    registration = create_registration unless registration
    update_registration(registration, form)
    registration.save
  end

  private

    def find_registration(key)
      registration = Registration[:id => key]
     # This is the sequel equivalent of Registration.Find(key) in ActiveRecord
    end

    def create_registration
      registration = Registration.new
      registration
    end

    def update_form(form, registration)
      form.update(
        :key => registration.id,
        :name => registration.name,
        :email => registration.email)
      form
    end

    def update_registration(registration, form)
      registration.name = form[:name]
      registration.email = form[:email]
    end
end
# The ORM representation (using Sequel as my ORM library)
class Registration < Sequel::Model
  set_schema do
    primary_key :id
    varchar :name
    varchar :email
  end
end

Maybe this is something that other folk have already thought of, and I am just catching up, but the proliferation of web MVC style frameworks which mandate persistence layers (eg Rails) makes be think that this may need to be revisited.