ORM: Data Mapper vs Active Record
Which one is better and why?
Found a typo? Edit meORM stands for Object-Relational Mapping, that is, the technique that transforms Objects from OOP into rows in the database and vice versa.
There are two patterns:
- Active Record: The record (entity) itself can actively change the DB
- Data Mapper: There is an external object that persists the entities
I will skip everything related to the DB setup like the XML configuration files for the Data Mapper and the hasOne() / hasMany() methods for the Active Record.
Active Record
As I previously mentioned, the entity itself can be created, updated or deleted. In PHP for example, Eloquent is an Active Record ORM developed by the Laravel community.
Data Mapper
In the data mapper, we need an external class that will update the DB. In PHP for example, Doctrine is the de facto Data Mapper ORM for Symfony.
So far, the code was very similar in both situations, you have to create a specific entity object, (for simplicity) we
used a createFrom()
named-constructor in both snippets and we called save()
or persist()
and flush()
depending
on the scenario.
Although, if you take a look at both snippets, you can see already the Data Mapper is using an external
dependency (Entity Manager
object) which is odd and clearly, is harder if you decide to introduce some tests to
the UserCreator
class, meanwhile in the Active Record
class, the entities are saving themselves, so we don’t have
any dependency at a glance, but that is not completely true, the entity itself has knowledge of the DB, and it will be
difficult to write some tests if we use the User
entity directly.
Repository Pattern
The repository pattern is a design pattern that hides the database logic into a new class, exposing only the methods we want to provide to the user.
In order to do this, we need to create an interface and a class that will implement the interface where we will drop all logic.
# App/User/Domain
{
;
}
~~~~
# App/User/Infrastructure
So the last step is to define which class will be resolved when we inject our UserRepository
interface, and finally,
our UserCreator
will be like:
Regarding tests, with the current UserCreator
implementation, it would be really simple to add a unit test, but it
won’t make sense as the saving logic would be mocked, and the test would provide no value at all.
A functional test where we check the user and the address was actually persisted in the database properly makes more
sense, but I will skip the test as it would add unnecessary complexity to the post 🙂