© DrHitch/Shutterstock.com
Clojure

3 Zugriff auf relationale Datenbanken in Clojure mit Korma


Korma [1] ist ein aromatisches Gericht aus dem südasiatischen Raum, das seinen Geschmack vor allem der harmonischen Komposition aus verschiedenen Gewürzen verdankt. Korma für Clojure [2] kombiniert Funktionen und Makros zu einer DSL für relationale Datenbanken – und verleiht der Arbeit mit SQL damit funktionale Würze.

In Clojure ist zur Datenhaltung häufig die Map das Mittel der Wahl. Deshalb stellt der aus objektorientierten Sprachen bekannte Impedance Mismatch [3] hier ein weniger schwerwiegendes Problem dar. Die Zeilen einer Datenbank lassen sich leicht in eine Liste von Maps überführen und umgekehrt. Trotzdem will man auch in Clojure ein konsistentes Datenmodell definieren und möglichst keine SQL-Strings direkt im Code schreiben. Korma geht zum Lösen dieser Aufgabe den Weg der eingebetteten DSL, wofür sich funktionale Sprachen in der Regel gut eignen. Dieses Kapitel gibt eine Einführung in die bei Korma verwendeten Konstrukte und zeigt deren Verwendung anhand eines einfachen fachlichen Beispiels.

Einbinden in das Clojure-Projekt

Bei Verwendung von Leiningen als Build-Tool wird Korma einfach per Dependency in der project.clj in ein Clojure-Projekt eingebunden. Die im Moment aktuelle Version ist 0.3.1.

Da Korma JDBC verwendet, sind für alle gängigen Datenbankmanagementsysteme Treiber vorhanden. Um einen Treiber zu verwenden, muss dieser zunächst ebenfalls als Abhängigkeit in der Projektdatei definiert werden (Listing 3.1).

(defproject
korma-example
"0.1.0-SNAPSHOT"
:dependencies
[[korma "0.3.1"]
[mysql/mysql-connector-java "5.1.30"]])

Listing 3.1: project.clj

Datenbank konfigurieren

Man gibt die Datenbankkonfiguration im Clojure-Code als Map an. Diese Map enthält den Klassennamen des JDBC-Treibers und weitere vom gewählten Treiber abhängige Optionen. Alternativ gibt es auch Helper-Funktionen, die bereits sinnvolle Defaults für die Konfiguration einer Datenbank mitbringen (Listing 3.2).

(use 'korma.db) 

(def db-config
(mysql
{:db "example-db"
:user "example"
:password "example"}))

(defdb example-db db-config)

Listing 3.2: DB-Konfiguration mit Helper-Funktion für MySQL

Entities definieren

Ist die Datenbank einmal konfiguriert, werden als Nächstes die Entities definiert, die in der Datenbank abgelegt werden sollen. Im einfachsten Fall übergibt man dem defentity-Makro nur den Namen der Entity als Parameter. Dazu muss die Tabelle in der Datenbank den gleichen Namen wie die Entity haben. Ist dies nicht der Fall, verwendet man die Helper-Funktion table, um den Tabellennamen anzugeben. Dabei kann der Tabellenname auch als Clojure-Keyword anstatt als String übergeben werden. defentity akzeptiert noch eine weitere Funktion pk, mit der man eine vom Standard (id) abweichende Spalte für den Primärschlüssel angeben kann.

Zusätzlich kann die Entity durch eine Reihe weiterer Optionen konfiguriert werden. Mit entity-fields wird angegeben, welche Spalten per Default in einem Select abgefragt werden sollen, falls im Select selbst keine genauere Definition erfolgt. Wird diese Option weggelassen, selektiert Korma automatisch alle Attribute. Mit den Optionen has-one, has-many, belongs_to und many_to_many werden Relationen zu andere...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang