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.