This document discusses object-relational mappers (ORMs) and several ORM libraries for Go. ORMs allow converting data between object-oriented programming languages and relational databases. While initially hailed, ORMs were later criticized for some assumptions that cost dearly. The document then outlines Go's philosophy regarding ORMs and duality between classes and types. Several popular Go ORM libraries are described, including Gorm, Gorp, and Sqlx, outlining their key features and support for operations like CRUD, relationships, and migrations. The document cautions to avoid opaque struct tags that can introduce semantic errors and to do application logic outside ORM objects.
2. ORM
● Object Relational Mapping
○ Convert data between two different type
systems
○ In memory representation of domain objects
(better abstractions of reality)
3. ORMs thus far….
● Hailed as worthwhile at first
● Tagged unusable by some as time went on
● Some assumptions made that cost dearly
● Leading to some hot debates.
● But they are still around.
4. Why?
● Structure / Modularity(The M in MVC, Object Representation / Relational Mapping)
● Agnostic Database Integration (configs)
● Boilerplate Reduction (Spaghetti, Complex Queries, DRY)
● Providing hooks Tx lifecycle (Before/After)
● Easier data validation (Maintaining Data integrity)
● Sensible Defaults (Better naming, Connascence/Cognizance etc)
● RAW SQL strings have a high chance of compiling
with semantic errors and @ runtime.
5. How?
● Support for popular databases
● CRUD
● SQL Generation
● Relationships / Association Traversals
● Tx hooks
● Schema Migration
● Managing Cache (???)
6. Go’s Philosophy
● As it Affects ORMs
○ Duality (Class / Type)
○ Non existence of a type hierarchy
■ Struct embedding (Composition)
■ Plumbing not encouraged
■ they don't have to announce their
relationships
7. Go ORMs
❖ jinzhu/gorm
❖ coopernurse/gorp
❖ astaxie/beedb now
beego/orm
❖ go-xorm/xorm
❖ coocood/qbs
❖ upper.io/db
❖ eaigner/hood
❖ Not regarded as ORMs
➢ jmoiron/sqlx
➢ eaigner/jet
➢ jaekwon/go-modeldb
8. database/sql
package models
// Author model
type Author struct {
ID int64 `db:"ID"json:"id"`
Name string `db:"display_name"json:"name"`
NickName string `db:"user_nicename"json:"nickname"`
Email string `db:"user_email"json:"email"`
URL string `db:"user_url"json:"url"`
}
db, _ := sql.Open("mysql", os.Getenv("SQL_MYSQL_DSN")")
9. database/sql
db.Exec(
"INSERT INTO author (display_name, user_nicename, email, url) VALUES (?, ?, ?)",
"Foo", "Bar", 'we@gfb.com', 'gfb.com/author/1'
)
row := db.QueryRow("SELECT id, display_name, user_nicename, email, url FROM users WHERE id = ?", 1)
row.Scan(&author.ID, &author.Name, &author.NickName, &author.Email, &author.URL)
db.Exec(
"UPDATE author SET display_name=?, user_nicename=?, email=?, url=? WHERE id = ?",
&author.ID, &author.Name, &author.NickName, &author.Email, &author.URL
)
db.Exec(
"DELETE FROM author WHERE id = ?",
author.ID
)
10. coopernurse/gorp
1. Supports MySQL, PostgresSQL, SQLite
2. CRUD
3. SQL migrations
a. dbmap.CreateTables()
b. dbmap.CreateTablesIfNotExists()
4. Hooks (PostGet,PreInsert ,PostInser,PreUpdat,PostUpdat,PreDelet,PostDelete)
5. Bind arbitrary SQL queries to a struct
6. Bind slice to SELECT query results without type assertions
7. Use positional or named bind parameters in custom SELECT queries
8. more..
var posts []Post
_, err = dbmap.Select(&posts, "select * from posts order by post_id")
11. jmoiron/sqlx
1. Is not regarded as an ORM from the authors view (I kind of disagree and agree to some extent)
2. Supports MySQL, PostgresSQL, SQLite
3. CRUD
4. Bind arbitrary SQL queries to a struct
a. Scannability (scan safety)
b. sql = fmt.Sprintf(`SELECT * FROM comments WHERE comment_approved <> 'spam'
AND comment_post_ID IN (%s)`, pIDs)
err = db.Unsafe().Select(&comments, sql)
5. A lot more flexible and better for legacy database
12. jinzhu/gorm
1. Supports MySQL, PostgreSQL, SQLite
2. Heavily influenced by Activerecord
3. CRUD
authors := []Author{}
err = db.Select(&authors, "SELECT * FROM author")
db.Save(&Author{Name: "Foo", NickName: "Bar", Email: 'we@gfb.com', URL: 'gfb.com/author/1'})
author.FirstName = "Big"
db.Save(author)
db.Delete(author)
4. Schema migrations
a. db.AutoMigrate(&Author{})
b. db.CreateTable(&Author{})
c. db.DropTable(&User{}) and db.DropTableIfExists(&User{})
5. Polymorphism and more...
6. Legacy DB support not great, A lot better for starting from scratch
13. Noteworthy
● Serialization is implemented the same way on all
● Be careful of go struct tags opaque strings which
happily compile with semantic errors and can fail
at runtime all too easily.
● Easily write verbose code
● Do all your logic outside your Go Structs (DAO)
● Avoid using YAML, JSON or XML for
configuration (Deployment is a bit steep) Use ENV
instead.