GORM ein OR-Mapper (ORM) für Golang

GORM ein OR-Mapper (ORM) für Golang

Im Artikel Datenbankzugriffe mit Go wurde gezeigt wie man mittels SQL Datenbankzugriffe mit Golang umsetzen kann. In diesem Artikel soll hingegeben ein Objektrelationaler-Mapper (OR-Mapper) eingesetzt werden.

Im Internet findet man einige Bibliotheken, die den Zugriff auf Datenbanken von Go aus erleichtern sollen. Nicht bei allen handelt es sich um "klassische" OR-Mapper. Einge von Ihnen erweitern den Umfang des Golang sql Packages, damit man einfacher und komfortabler damit arbeiten kann.

Bei der Auswahl der richtigen Bibliothek für das eigene Projekt darf man nie die eigene Datenbank aus dem Auge lassen. Es ist immer zu prüfen ob die ausgewählte Bibliothek auch mit der eigenen Datenbank eingesetzt werden kann. Oftmals ist man z. B. mit einer IBM DB2 Datenbank offiziell außen vor. Mit MySQL, PostgreSQL, Sqlite3 und SQL Server sollte man keine großen Probleme zu befürchten zu haben.

NameUrlStars bei GitHubAnmerkung
gormhttp://gorm.ioca. 12000"Full-Featured ORM (almost)" - offiziell für MySQL, PostgreSQL, Sqlite3 und SQL Server
beegohttps://github.com/astaxie/beego/ca. 19000"It is heavily influenced by Django ORM, SQLAlchemy." - für MySQL, PostgreSQL, Sqlite3
upper.iohttp://upper.ioca. 1600"Productive data access layer for Go" - Adapter für PostgreSQL, MySQL, SQLite, QL, SQL Server, MongoDB
sqlxhttp://jmoiron.github.io/sqlx/ca. 5600"sqlx is a library which provides a set of extensions on go's standard database/sql library."
xormhttp://xorm.io/ca. 4300"Simple & Powerful ORM Framework for Go Programming Language" - Support für Mysql, MyMysql, Postgres, Tidb, SQLite, MsSql, Oracle
gorphttps://github.com/go-gorp/gorpca. 3000"Go Relational Persistence" - wird nicht aktiv entwickelt
pghttps://github.com/go-pg/pgca. 2300"PostgreSQL client and ORM for Golang"
sqlboilerhttps://github.com/volatiletech/sqlboilerca.2000SQLBoiler is a tool to generate a Go ORM tailored to your database schema.

Dieser Artikel greift sich GORM The fantastic ORM library for Golang heraus und stellt ihn kurz vor.

GORM Installation mit Treiber

Die Installation von GORM erfolgt go-typisch über

go get -u github.com/jinzhu/gorm

Da in diesem Beispiel mit einer SQLlite Datenbank gearbeitet werden soll muss zusätzlich noch ein DB Treiber installiert werden. Hier wird der go-sqlite3 Treiber verwendet.

go get github.com/mattn/go-sqlite3

Jetzt können die Abhängigkeiten in das eigene Go Programm importiert werden.

import (
    "github.com/jinzhu/gorm"
    _ "github.com/jinzhu/gorm/dialects/sqlite"
)

Objektmodell

Das Objektmodell ist im ersten Schritt recht einfach gehalten. Es handelt sich um einen Kunden mit Vor- und Nachname. Weitere Metainformationen für das Modell lassen sich über Tags definieren.

type Customer struct {
	gorm.Model
	FirstName string
	LastName  string
}

Dieser soll im weiteren in der Datenbank abgelegt werden. GORM bietet natürlich auch Relationen bzw. Beziehungen zwischen den Objekten an. (Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)) Der Artikel Relationen mit GORM einem OR-Mapper für Golang zeigt diese Möglichkeiten.

Ab in die DB

Verbindung aufbauen

Im nächsten Schritt muss eine Datenbankverbindung zu einer SQLlite Datenbank aufgebaut werden. Dies geschieht über einen Open() Aufruf aus dem Package gorm.

db, err := gorm.Open("sqlite3", "test.db")
if err != nil {
	panic("failed to connect database")
}
defer db.Close()

DB Schema aktualisieren

Nachdem eine Verbindung zur DB konfiguriert wurde, sorgen wir dafür, dass die für unser Objekt benötigten Tabellen mit Spalten in der DB vorhanden sind. Dies erfolgt mit einem Aufruf von AutoMigrate(). Als Parameter wird der entsprechende Struct mitgegeben.

db.AutoMigrate(&Customer{})

An dieser Stelle könnte man natürlich eine Liste von Typen mitgeben.

WARNING: AutoMigrate will ONLY create tables, missing columns and missing indexes, and WON’T change existing column’s type or delete unused columns to protect your data.

Gorm hat in diesem Fall folgende Tabelle customers angelegt:

Nametype
idinteger
created_atdatetime
updated_atdatetime
deleted_atdatetime
first_namevarchar(255)
last_namevarchar(255)

Mehr zur Migration findet man auch direkt auf der Projektseite. Hier werden auch Features zur manuellen Migration gezeigt. Wenn also der Automatismus nicht ausreicht.

Daten Schreiben und Lesen

Das Anlegen von Datensätzen funktioniert wie man sich das bei einem OR-Mapper vorstellt:

//Objekt anlegen
customer := Customer{FirstName: "Hans2", LastName: "wurst"}

//Objekt persistieren
db.Create(&customer)

Daten können ebenfalls recht einfach wieder gelesen werden:

//Daten Lesen
var foundCustomer Customer
db.First(&foundCustomer, "First_Name = ?", "Hans2")

//Ausgabe
fmt.Println("Gefunden wurde:", foundCustomer.FirstName)

Zu Beachten ist hier, dass man bei dieser Abfrage das SQL Schema im Blick haben muss. Es handelt sich hierbei um eine "Plain SQL" Abfrage.

Alternativ lässte sich eine Abfrage über eine Vorlage durchführen. So kann man ohne Kenntnisse des darunterliegenden Schemata auf die Daten zugreifen.

db.Where(&Customer{FirstName: "Hans"}).First(&foundCustomer)

Eine Aktualisierung erfolgt über einen Update Call:

// Update
db.Model(&foundCustomer).Update("LastName", "Meiser")

Löschen funktioniert analog:

db.Delete(&foundCustomer)

Wenn man sich nach dem Löschen die Datenbank anschaut, darf man nicht erschrecken. Im ersten Moment würde man erwarten, dass die Tabelle leer ist. Das ist allerdings nicht der Fall, da GORM den Datensatz "nur" als gelöscht markiert. Der Wert für deleted_at ist entsprechend gefüllt.

Logging

Für den Fall dass man ich etwas mehr anschauen möchte was GORM so macht, kann man das Logging einschalten. Setzt man den LogMode werden die SQL Statements sowie etwas Metadaten mit ausgegeben.

db.LogMode(true)

Error Handling

Die Auswertung von Fehlern unterscheidet sich vom sonstigen Vorgehen bei Go/Golang. Bei den Datenbankzugriffen bekommt man nicht direkt einen Fehler zurück, auf den man reagieren kann. Grund dafür ist das Fluent-API von GORM. Aufrufe können verkettet werden. Hier ein Beispiel von der Projekt Seite

db.Where("name LIKE ?", "jinzhu%").Find(&users, "id IN (?)", []int{1, 2, 3}).Count(&count)

Durch die Verkettung kann man nicht direkt die Fehler auswerten. Stattdessen gibt es ein Error Feld an *gorm.DB das abgefragt werden kann.

err = db.Delete(&foundCustomer).Error
if err != nil {
	panic(err)
}

Für den Fall dass mehrere Fehler in einer Verarbeitung auftreten, können diese über GetErrors() abgerufen werden. Das ist bei verketteten Aufrufen unter Umständen der Fall.

db.First(&user).Limit(10).Find(&users).GetErrors()

Komplettes Beispiel

Das komplette Beispiel kann auch in GitHub gefunden werden.

package main

import (
	"fmt"

	"github.com/jinzhu/gorm"
	_ "github.com/jinzhu/gorm/dialects/sqlite"
)

type Customer struct {
	gorm.Model
	FirstName string
	LastName  string
}

func main() {
	db, err := gorm.Open("sqlite3", "test.db")
	if err != nil {
		panic("failed to connect database")
	}
	defer db.Close()

	// LogMode enable
	db.LogMode(true)

	// Migrate the schema
	db.AutoMigrate(&Customer{})

	// Create
	customer := Customer{FirstName: "Hans", LastName: "wurst"}
	db.Create(&customer)

	var foundCustomer Customer
	// Plain SQL
	db.First(&foundCustomer, "First_Name = ?", "Hans")
	// Template
	db.Where(&Customer{FirstName: "Hans"}).First(&foundCustomer)

	fmt.Println("Gefunden wurde:", foundCustomer.FirstName)

	// Update - update product's price to 2000
	db.Model(&foundCustomer).Update("LastName", "Meiser")

	err = db.Delete(&foundCustomer).Error
	if err != nil {
		panic(err)
	}

}

29.01.2019

 

Kennen Sie schon das Buch zum Thema?

Der praktische Soforteinstieg für Developer und Softwarearchitekten, die direkt mit Go produktiv werden wollen.

  • Von den Sprachgrundlagen bis zur Qualitätssicherung
  • Architekturstil verstehen und direkt anwenden
  • Idiomatic Go, gRPC, Go Cloud Development Kit
  • Cloud-native Anwendungen erstellen
Microservices mit Go Buch

zur Buchseite beim Rheinwerk Verlag Rheinwerk Computing, ISBN 978-3-8362-7559-0 (als PDF, EPUB, MOBI und Papier)

Kontakt

Source Fellows GmbH

Source Fellows GmbH Logo

Lerchenstraße 31

72762 Reutlingen

Telefon: (0049) 07121 6969 802

E-Mail: info@source-fellows.com