Was ist der Unterschied zwischen Active Record und Data Mapper?

Früher oder später geht es in jeder Webapplikation darum Daten zu speichern. In einer nach dem MVC-Prinzip orientierten Anwendung wird die ein oder andere Form eines ORM zum Einsatz kommen. Solche ORM (z. B. Doctrine, Eloquent) folgen entweder dem Paradigma des Active Record oder das dem Data Mapper. In diesem Artikel wird es um die Unterschiede dieser beiden gehen.


Was ist überhaupt ein ORM?

ORM ist die Abkürzung für „object-relational mapping“ zu deutsch Objektrelationale Abbildung. Damit ist in der Anwendung eine Abstraktionsebene gemeint, die die relationalen Daten aus einem Speichermedium (z. B. Datenbank oder Datei) mit Objekten im Programmcode verknüpft.

Ein ORM enthält die notwendigen Logiken für die üblichen Operationen, die wir mit einem Datenobjekt anstellen wollen. Diese werden für gewöhnlich mit CRUD abgekürzt. CRUD steht für create, read, update, delete also anlegen, laden, bearbeiten und löschen. Im Falle einer Datenbank übernimmt das ORM also die SQL-Befehle für uns.


Das Active Record Pattern

Beim Ansatz des Active Record gibt es eine Basisklasse, die vom ORM zur Verfügung gestellt wird, und von der alle unsere Models erben. Diese Basisklasse enthält dann zumindest für jede CRUD-Operation eine Methode.

Ein entsprechendes Interface könnte zum Beispiel so aussehen:

Es hat sich eingebürgert die Methoden zum Laden der Objekte mit find zu benennen. Gespeichert werden die Datensätze normalerweise mit save.

Da wir beim Laden noch keine Instanz unseres Models haben sind die find Methoden static und liefern eine Instanz von sich selbst.

Die save Methode wird so implementiert, dass sie selbstständig erkennt, ob das Objekt neu angelegt oder aktualisiert wurde – zumeist anhand eines eindeutigen Indexes.

Zusammengefasst heißt das, das Model enthält selbst (durch Vererbung) die Logiken zur Verwaltung.

Anwendungsbeispiel: Erstellen eines neuen Datensatzes

Anwendungsbeispiel: Aktualisieren eines Datensatzes

 


Das Data Mapper Pattern

Bei einem Data Mapper handelt sich um einen separaten Service, der unsere Models verwaltet und CRUD-Operationen zur Verfügung stellt.

Ein Interface für einen Data Mapper könnte so aussehen:

Da es sich um einen Service (also eigenständige Klasse) handelt, gibt es hier keine statischen Methoden. Allerdings muss dem Data Mapper beim Laden von Datensätzen mitgeteilt werden, um welche Objekte es sich handelt. Die find Methoden liefern dann ein oder mehrere Instanzen der entsprechenden Modelklasse zurück.

Datensätze anlegen und aktualisieren läuft über die Methode persist. Löschen über remove.

Für gewöhnlich werden Speichervorgänge beim Data Mapper nicht sofort ausgeführt, sondern nur gesammelt und erst beim Aufruf von flush in einer Datenbankoperation abgeschickt.

Anwendungsbeispiel: Erstellen eines neuen Datensatzes

Anwendungsbeispiel: Aktualisieren eines Datensatzes

 


Die Unterschiede von Active Record und Data Mapper

Unterschiedliche Komplexität

Die Vorgehensweise beim Data Mapper erfordert einen zusätzlichen Service, der die Komplexität der Anwendung etwas erhöht. Jede Komponente, die irgendetwas mit Daten macht (also fast alle) benötigt Zugang zu diesem Service. Active Record ist hier einfacher in der Handhabung.

Flexibles Speichermedium

Nicht jede Anwendung bezieht ihre Daten ausschließlich aus einer Datenbank. Hin und wieder spielen auch Dateien (.ini, .yml, .xml, …) eine Rolle. Hier hilft das Prinzip des Data Mapper, da dieser bestimmt wie ein Model konkret abgespeichert wird. Innerhalb der Models gibt es keinen Unterschied.

Anders bei Active Record: Hier muss sich das Model entscheiden, von welcher Basisklasse es erbt. Damit ist dann auch die Wahl des Speichermediums (für immer) entschieden. Mehr Flexibilität bietet hier also Data Mapper.

Abhängigkeiten innerhalb der Daten

In vielen Anwendungen wird es Abhängigkeiten innerhalb der Datenstrukturen (und damit Models) geben. Diese sog. Geschäftslogik muss vom Programm eingehalten werden. Bei Active Record ist für gewöhnlich der „Nutzer“ – also zum Beispiel ein Controller – selbst verantwortlich. Hier können sich leicht Fehler einschleichen, insbesondere, wenn an verschiedenen Stellen mit den gleichen Daten gearbeitet werden muss (z. B. Frontend und Admin).

Der Model-Manager des Data Mapper übernimmt dieses Aufgabe. In der Konfiguration der Models werden die Abhängigkeiten festgelegt und bei jeder Operation vom Model-Manager automatisch eingehalten.

Transaktionen

Sollen mehrere Datenbankaktionen atomar (also alle oder keine) erfolgen, sind Transaktionen notwendig. Wie schon bei der Geschäftslogik muss sich mit Active Record selbst darum gekümmert werden.

Wie wir oben gesehen haben, werden hingegen beim Data Mapper von Haus aus mit persist alle Operationen gesammelt und als eine Einheit mit flush abgesetzt.


Was ist denn jetzt besser?

Wie oft in der Programmierung kann auch hier die Antwort nur lauten: „Kommt darauf an.“

Besteht die Anwendung größtenteils aus CRUD-Operationen einzelner Datenobjekte, wird Active Record die bessere Wahl sein.

Gibt es hingegen gewachsene und komplexe Geschäftslogiken, wird ein Data Mapper die Prozesse vereinfachen.