カテゴリー: BackEnd

Go言語で使えるORMライブラリ

はじめに

以前、Go言語で使えるmigrationライブラリを紹介しました。今回はORMライブラリを紹介します。

ORMライブラリ

Go言語のORMライブラリを2つ紹介します。これらのライブラリを使用することで、DBのデータをstructにマッピングすることができます。それでは、各ライブラリの特徴を簡単に紹介します。

GORM

GORMは「Full-Featured ORM」や「Developer Friendly」を謳う非常に多機能な定番ORMで、これ単体で一通りのことができます。また、ドキュメントも豊富です。
GORMの機能を以下に列挙します。

  • Associations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)
  • Hooks (Before/After Create/Save/Update/Delete/Find)
  • Preloading (eager loading)
  • Transactions
  • Composite Primary Key
  • SQL Builder
  • Auto Migrations
  • Logger
  • Extendable, write Plugins based on GORM callbacks
  • Every feature comes with tests

SQLBoiler

SQLBoilerは非常にパフォーマンスの高いORMのようです。migration機能はないので、goose、 sql-migrateや前回紹介したsqldefなどを併用する必要があります。SQLBoilerの使い方についてはこちらが参考になります。

GORMを使ってみる

それでは、実際にGORMを使ってみます。

導入

下記の通りインストールします。

$ go get -u github.com/jinzhu/gorm

今回はMySQLを使用しますので、こちらもインストールしておきます。

$ go get -u github.com/go-sql-driver/mysql

migration

nameというフィールドを持つUsersというテーブルを定義します。下記のようにgorm.Modelと記述するとcreated_at、updated_at、deleted_atが定義されます。

type User struct {
 gorm.Model
 Name string
}

マイグレーションは下記のように行います。
?parseTime=trueを記述しないと「unsupported Scan, storing driver.Value type []uint8 into type *time.Time」というエラーが発生します。こちらの通りDB側の型とGo言語側の型が違うことで発生するようです。

// user_name:password@host/database_name
db, err := gorm.Open("mysql", "root:root@tcp(127.0.0.1:3306)/gorm_test?parseTime=true")
if err != nil {
 panic("failed to connect }
defer db.Close()

db.AutoMigrate(&User{})
if db.Error != nil {
 panic(db.Error)
}

実際のテーブルは下記のとおりです。

mysql> desc users;
+------------+------------------+------+-----+---------+----------------+
| Field      | Type             | Null | Key | Default | Extra          |
+------------+------------------+------+-----+---------+----------------+
| id         | int(10) unsigned | NO   | PRI | NULL    | auto_increment |
| created_at | timestamp        | YES  |     | NULL    |                |
| updated_at | timestamp        | YES  |     | NULL    |                |
| deleted_at | timestamp        | YES  | MUL | NULL    |                |
| name       | varchar(255)     | YES  |     | NULL    |                |
+------------+------------------+------+-----+---------+----------------+

insert

insertは下記のように行います。

var newUser = &User{Name: "Yamada"}
db = db.Create(newUser)
if db.Error != nil {
 panic(db.Error)
}

select

selectは下記のように行います。

var user User
db.First(&user, "name = ?", "Yamada")
if db.Error != nil {
 panic(db.Error)
}

update

updateは下記のように行います。

var user User
db.First(&user, "name = ?", "Yamada")
if db.Error != nil {
 panic(db.Error)
}

user.Name = "Tanaka"
db.Save(&user)

delete

deleteは下記のように行います。

var user User
db.First(&user, "name = ?", "Yamada")
if db.Error != nil {
 panic(db.Error)
}

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

サンプルコード

CRUD操作のサンプルコードは下記のとおりです。

package main

import (
 "encoding/json"
 "fmt"
 "github.com/jinzhu/gorm"
 _ "github.com/jinzhu/gorm/dialects/mysql"
)

type User struct {
 gorm.Model
 Name string
}

func main() {
 db, err := gorm.Open("mysql", "root:root@tcp(127.0.0.1:3306)/gorm_test?parseTime=true")
 if err != nil {
  panic("failed to connect database")
 }
 defer db.Close()

 db.LogMode(true)

 var newUser = &User{Name: "Yamada"}
 db.AutoMigrate(&User{})
 if db.Error != nil {
  panic(db.Error)
 }
 db = db.Create(newUser)
 if db.Error != nil {
  panic(db.Error)
 }

 j, _ := json.Marshal(newUser)
 fmt.Println(string(j))

 var user User
 db.First(&user, "name = ?", "Yamada")
 if db.Error != nil {
  panic(db.Error)
 }

 j, _ = json.Marshal(user)
 fmt.Println(string(j))

 user.Name = "Tanaka"
 db.Save(&user)

 db.First(&user, "name = ?", "Tanaka")
 if db.Error != nil {
  panic(db.Error)
 }

 j, _ = json.Marshal(user)
 fmt.Println(string(j))

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

実行時のログは下記のとおりです。

$ go run main.go 

(/Users/***/dev/src/test_gorm/main.go:29) 
[2018-11-18 12:07:38]  [1.01ms]  INSERT INTO `users` (`created_at`,`updated_at`,`deleted_at`,`name`) VALUES ('2018-11-18 12:07:38','2018-11-18 12:07:38',NULL,'Yamada')  
[1 rows affected or returned ] 
{"ID":9,"CreatedAt":"2018-11-18T12:07:38.099754+09:00","UpdatedAt":"2018-11-18T12:07:38.099754+09:00","DeletedAt":null,"Name":"Yamada"}

(/Users/***/dev/src/test_gorm/main.go:38) 
[2018-11-18 12:07:38]  [0.58ms]  SELECT * FROM `users`  WHERE `users`.`deleted_at` IS NULL AND ((name = 'Yamada')) ORDER BY `users`.`id` ASC LIMIT 1  
[1 rows affected or returned ] 
{"ID":9,"CreatedAt":"2018-11-18T03:07:38Z","UpdatedAt":"2018-11-18T103:07:38Z","DeletedAt":null,"Name":"Yamada"}

(/Users/***/dev/src/test_gorm/main.go:47) 
[2018-11-18 12:07:38]  [0.40ms]  UPDATE `users` SET `created_at` = '2018-11-18 18:07:38', `updated_at` = '2018-11-18 12:07:38', `deleted_at` = NULL, `name` = 'Tanaka'  WHERE `users`.`deleted_at` IS NULL AND `users`.`id` = '9'  
[1 rows affected or returned ] 

(/Users/***/dev/src/test_gorm/main.go:49) 
[2018-11-18 12:07:38]  [0.40ms]  SELECT * FROM `users`  WHERE `users`.`deleted_at` IS NULL AND `users`.`id` = '9' AND ((name = 'Tanaka')) ORDER BY `users`.`id` ASC LIMIT 1  
[1 rows affected or returned ] 
{"ID":9,"CreatedAt":"2018-11-18T03:07:38Z","UpdatedAt":"2018-11-18T03:07:38Z","DeletedAt":null,"Name":"Tanaka"}

(/Users/***/dev/src/test_gorm/main.go:57) 
[2018-11-18 12:07:38]  [0.40ms]  UPDATE `users` SET `deleted_at`='2018-11-18 12:07:38'  WHERE `users`.`deleted_at` IS NULL AND `users`.`id` = '9'  
[1 rows affected or returned ]

さいごに

今回はGo言語でのORMライブラリを紹介しました。今回はGORMを使ってみましたが、SQLBoilerも実際に動かしてみたいと思います。

なお、Go言語に関してはこちらでも多くの記事を紹介していますので、ぜひご覧ください。

おすすめ書籍

      

Hiroki Ono

シェア
執筆者:
Hiroki Ono
タグ: golangGo言語

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

4週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

1か月 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前