ORM (Objektrelationales Mapping) ist eine Technik, die die Lücke zwischen objektorientierter Programmierung und relationalen Datenbanken schließt. Klassen werden auf Tabellen abgebildet, Objekte auf Zeilen und Attribute auf Spalten – so arbeiten Entwickler mit vertrauten Objekten, statt SQL-Strings zu schreiben.
Das Problem: Impedance Mismatch
Relationale Datenbanken speichern Daten in Tabellen mit Zeilen und Spalten; moderne Sprachen arbeiten mit Objekten, Vererbung und Sammlungen. Diese unterschiedlichen Modelle werden Impedance Mismatch genannt. ORM übersetzt zwischen beiden Welten und spart dadurch viel Boilerplate-Code.
Wie ORM funktioniert
Ein ORM-Framework bindet zur Laufzeit Klassen an Tabellen (Mapping). Beim Speichern erzeugt es automatisch INSERT/UPDATE, beim Laden baut es Objekte aus SELECT-Ergebnissen. Beziehungen wie 1:n oder n:m werden über Fremdschlüssel abgebildet (siehe Primär- und Fremdschlüssel) – das ORM erzeugt daraus die passenden JOINs (siehe SQL: JOINs richtig verstehen).
Vorteile
- Weniger Code: CRUD-Operationen ohne manuelle SQL-Statements
- Typsicherheit: Fehler werden oft schon beim Kompilieren erkannt
- Portabilität: Das ORM erzeugt Dialekt-spezifisches SQL für verschiedene Datenbanken
- Sicherheit: Parameterisierung verhindert SQL-Injection
Nachteile und Fallstricke
- N+1-Problem: Beim Laden einer Liste mit Beziehungen erzeugt naives ORM pro Zeile eine zusätzliche Query – Abhilfe: Eager Loading oder Joins
- Lazy Loading: verzögerter Zugriff kann zu unerwarteten Queries führen
- Komplexe Abfragen: schwierige Queries sind in reinem SQL oft lesbarer und schneller
- Performance-Overhead: das generierte SQL ist nicht immer optimal – dann greift man gezielt zu rohem SQL oder Views
Bekannte ORM-Frameworks
| Sprache | ORM |
|---|---|
| Java | Hibernate, JPA |
| C#/.NET | Entity Framework Core |
| Python | SQLAlchemy, Django ORM |
| PHP | Doctrine, Eloquent (Laravel) |
| Ruby | ActiveRecord (Rails) |
| JavaScript/TypeScript | Sequelize, Prisma, Drizzle |
| Go | GORM, ent |
| Rust | Diesel |
Beispiel mit Python/SQLAlchemy
from sqlalchemy import create_engine, Column, Integer, String
from sqlalchemy.orm import declarative_base, sessionmaker
engine = create_engine("postgresql://user:pass@localhost/firmendb")
Base = declarative_base()
class Kunde(Base):
__tablename__ = "kunden"
id = Column(Integer, primary_key=True)
name = Column(String)
session = sessionmaker(engine)()
neuer_kunde = Kunde(name="Hanse Computing")
session.add(neuer_kunde)
session.commit()
Damit die Datenbank hinter dem ORM sauber bleibt, spielen ein durchdachtes Datenbankschema und Normalisierung eine zentrale Rolle. Auch Indizes sind wichtig, damit die vom ORM erzeugten Queries schnell bleiben.