gormの使い方を自分向けにまとめました。適宜追加していきます。
基本的にこれがわかってたらなんとかなる。
そして大体公式ドキュメントに書いてあります!
以下のようなデータを用意して色々操作してみたいと思います。
# 初期状態
mysql> select * from persons;
+----+------+-----+-------+---------------------+---------------------+
| id | name | age | hobby | created_at | updated_at |
+----+------+-----+-------+---------------------+---------------------+
| 1 | A | 20 | NULL | 2018-10-04 11:13:35 | 2018-10-04 11:13:35 |
| 2 | B | 30 | c | 2018-10-04 11:13:35 | 2018-10-04 11:13:35 |
| 3 | C | 15 | NULL | 2018-10-04 11:13:35 | 2018-10-04 11:13:35 |
| 4 | D | 44 | d | 2018-10-04 11:13:35 | 2018-10-04 11:13:35 |
| 5 | E | 60 | NULL | 2018-10-04 11:13:35 | 2018-10-04 11:13:35 |
+----+------+-----+-------+---------------------+---------------------+
5 rows in set (0.00 sec)
// Go言語でのPeople定義
package main
import (
"time"
)
type Person struct {
Id int `json:"id" gorm:"primary_key"`
Name string `json:"name"`
Age int `json:"age"`
Hobby string `json:"hobby"`
CreatedAt time.Time `json:"createdAt" sql:"DEFAULT:current_timestamp"`
UpdatedAt time.Time `json:"updatedAT" sql:"DEFAULT:current_timestamp on update current_timestamp"`
}
最初の1件を取得する
var person Person
db.First(&person)
fmt.Printf("%+v\n", person)
// 出力結果
//{Id:1 Name:A Age:20 Hobby: CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}
// 実行SQL
// SELECT * FROM `people` ORDER BY `people`.`id` ASC LIMIT 1
文字列検索をする
var people []Person
db.Where("name = ?", "B").Find(&people)
fmt.Printf("%+v\n", people)
// 出力結果
// [{Id:2 Name:B Age:30 Hobby:c CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}]
// 実行SQL
// SELECT * FROM `people` WHERE (name = 'B')
並び替えをする
var people []Person
db.Order("age desc").Find(&people)
fmt.Printf("%+v\n", people)
// 出力結果
// [{Id:5 Name:E Age:60 Hobby: CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}
// {Id:4 Name:D Age:44 Hobby:d CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}
// {Id:2 Name:B Age:30 Hobby:c CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}
// {Id:1 Name:A Age:20 Hobby: CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}
// {Id:3 Name:C Age:15 Hobby: CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}]
// 実行SQL
// SELECT * FROM `people` ORDER BY age desc
取得件数を絞り込む
var people []Person
db.Order("age desc").Limit(3).Offset(1).Find(&people)
fmt.Printf("%+v\n", people)
// 実行結果
// [{Id:4 Name:D Age:44 Hobby:d CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}
// {Id:2 Name:B Age:30 Hobby:c CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}
// {Id:1 Name:A Age:20 Hobby: CreatedAt:2018-10-04 11:37:57 +0000 UTC UpdatedAt:2018-10-04 11:37:57 +0000 UTC}]
// 実行SQL
// SELECT * FROM `people` ORDER BY age desc LIMIT 3 OFFSET 1
データを登録する
f := Person{
Name: "F",
Age: 12,
}
db.Create(&f)
fmt.Printf("%+v\n", f)
このとき、hobbyはなにも設定していなかったですが実際DBには空が入ります。
mysql> select id from people where id = 6 and hobby is null;
Empty set (0.00 sec)
mysql> select id from people where id = 6 and hobby = "";
+----+
| id |
+----+
| 6 |
+----+
1 row in set (0.00 sec)
NULLを入れるには、対象のカラムの型をポインタにします。
type Person struct {
~~~
Hobby *string `json:"hobby"`
~~~
}
最後上記の処理を実行すると
mysql> select id from people where id = 7 and hobby is null ;
+----+
| id |
+----+
| 7 |
+----+
1 row in set (0.00 sec)
NULLが入っているのがわかります。
データを更新する
person := Person{ Id: 1 }
db.Model(&person).Update("hobby", "a")
fmt.Printf("%+v\n", person)
// 実行結果
// {Id:1 Name: Age:0 Hobby:a CreatedAt:0001-01-01 00:00:00 +0000 UTC UpdatedAt:2018-10-04 21:26:56.983776665 +0900 JST m=+0.003486322}
// 実行SQL
// UPDATE `people` SET `hobby` = 'a', `updated_at` = '2018-10-04 21:26:56' WHERE `people`.`id` = '1'
どうやらgormはUpdateのときはupdated_atに自動で値を入れてくれるみたいです。
実行後のレコード
mysql> select * from people where id = 1;
+----+------+-----+-------+---------------------+---------------------+
| id | name | age | hobby | created_at | updated_at |
+----+------+-----+-------+---------------------+---------------------+
| 1 | A | 20 | a | 2018-10-04 12:26:45 | 2018-10-04 12:26:57 |
+----+------+-----+-------+---------------------+---------------------+
1 row in set (0.00 sec)
nameやageはなにも設定してませんが、空になったりしませんでした。
意図して空にしてみたらどうなるんでしょうか?
person := Person{ Id: 1, Age: 0 }
db.Model(&person).Update(person)
fmt.Printf("%+v\n", person)
// 実行結果
// {Id:1 Name: Age:0 Hobby:<nil> CreatedAt:0001-01-01 00:00:00 +0000 UTC UpdatedAt:2018-10-04 23:40:35.479965986 +0900 JST m=+0.003397484}
// 実行SQL
// UPDATE `people` SET `id` = '1', `updated_at` = '2018-10-04 23:40:35' WHERE `people`.`id` = '1'
うーん、このやり方だとうまく動きません。
structでのintの初期値は0であるため、gormが検知できないんですね。
person := Person{ Id: 1 }
data := map[string]interface{} {
"age": 0,
}
db.Model(&person).Update(data)
fmt.Printf("%+v\n", person)
// 実行結果
// {Id:1 Name: Age:0 Hobby:<nil> CreatedAt:0001-01-01 00:00:00 +0000 UTC UpdatedAt:2018-10-04 23:46:12.378224923 +0900 JST m=+0.003037641}
// 実行SQL
// UPDATE `people` SET `age` = '0', `updated_at` = '2018-10-04 23:46:12' WHERE `people`.`id` = '1'
更新の際はStructを使うのではなく、mapを使うと意図した動きになりました。
データを削除する
person := Person{ Id: 5 }
db.Delete(&person)
// 実行SQL
// DELETE FROM `people` WHERE `people`.`id` = '5'