概要
GORMを初めて使用したので、基本的な使用方法をアウトプットのため投稿する。
■ Go version
go1.15.7
■ MySQL version
5.7.37
GORMを導入する
以下のコードで必要なパッケージをインストールすることができる。
go mod init [任意の値]
go get -u gorm.io/gorm
go get -u github.com/go-sql-driver/mysql
テーブルの作成
以下のコードでテーブルの作成・削除が可能であった。
GOのコード
package main
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
type Data1 struct {
gorm.Model
Title string
Content string
}
func main() {
dsn := "[ユーザー名]:[パスワード]@tcp(127.0.0.1:3306)/[スキーマ―名]?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
} else {
up01(dsn, db)
down01(dsn, db);
}
}
func up01(dsn string, db *gorm.DB) {
db.AutoMigrate(Data1{})
}
func down01(dsn string, db *gorm.DB) {
db.Migrator().DropTable(Data1{})
}
作成されるテーブル
CREATE TABLE `data1` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`created_at` datetime(3) DEFAULT NULL,
`updated_at` datetime(3) DEFAULT NULL,
`deleted_at` datetime(3) DEFAULT NULL,
`title` longtext,
`content` longtext,
PRIMARY KEY (`id`),
KEY `idx_data1_deleted_at` (`deleted_at`)
) ENGINE = InnoDB DEFAULT CHARSET = latin1
解説
1つ1つのコードの解説を記載する。
パッケージ
gorm.io/driver/mysql
gorm.io/gorm
GORMでMySQLを使用するパッケージを導入している。
以下にGItHubのリンクを記載している。
https://github.com/go-gorm/mysql
構造体
type Data1 struct {
gorm.Model
Title string
Content string
}
テーブルの生成・削除に使用する構造体を宣言している。
gorm.Model
の記述があることでID, CreatedAt, UpdatedAt, DeletedAt
カラムが構造体に記載せずともテーブルに反映されるようになる。
また、構造体名が小文字だと初期化時にフィールドには存在しているが、DB作成時にカラムが生成されていないので大文字にする必要がある。
データベースに接続
dsn := "[ユーザー名]:[パスワード]@tcp(127.0.0.1:3306)/[スキーマ―名]?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
こちらのページに詳細が記載されているが、上記コードでデータベースに接続可能であった。
ユーザー名、IPアドレス、ポート番号、charset等は各自の環境に合わせて変更する必要がある。
関数呼び出し
if err != nil {
panic("failed to connect database")
} else {
up01(dsn, db)
down01(dsn, db);
}
データベースに接続できた場合に関数を呼び出している。
現状だと2つの関数が実行されるので、テーブルを作成したい場合はdown01関数
の呼び出しをコメントアウトし、テーブルを削除したい場合はup01関数
の呼び出しをコメントアウトする。
テーブルの作成・削除を行う関数
func up01(dsn string, db *gorm.DB) {
db.AutoMigrate(Data1{})
}
func down01(dsn string, db *gorm.DB) {
db.Migrator().DropTable(Data1{})
}
上記内容でテーブルの作成・削除が可能である。
CRUD
以下のコードでCRUD機能を実装した。
解説を記載していく。
package main
import (
"fmt"
"gorm.io/gorm"
"gorm.io/driver/mysql"
)
// 構造体名を大文字にしないと以下のエラーになる
// 「struct field title has json tag but is not exportedstructtag」
type Data1 struct {
gorm.Model
Title string `json:"title"`
Content string `json:"content"`
}
func main() {
dsn := "[ユーザー名]:[パスワード]@tcp(127.0.0.1:3306)/[スキーマ―名]?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
panic("failed to connect database")
}
var data1 Data1
var data1_arr []Data1
// Create
db.Debug().Create(&Data1{Title: "title1", Content: "content1"})
// Create Multi
var multi_create = []Data1{{Title: "title2", Content: "content2"}, {Title: "title3", Content: "content3"}, {Title: "title4", Content: "content3"}}
db.Debug().Create(&multi_create)
// Read
db.Debug().First(&data1, 1)
fmt.Println(data1)
read_json, err := json.Marshal(data1)
fmt.Println(string(read_json))
// Read Multi
db.Debug().Find(&data1_arr)
fmt.Println(data1_arr)
read_multi_json, err := json.Marshal(data1_arr)
fmt.Println(string(read_multi_json))
// Update
db.Debug().Model(&Data1{}).Where("id = ?", 1).Update("Title", "titleUpdate")
// Update Multi
db.Debug().Model(&data1).Where("id = ?", 1).Updates(Data1{Title: "titleMultUpdate", Content: "ContentMultUpdate"})
// Delete
db.Debug().Delete(&data1, 1)
}
※Debug
メソッドはターミナルにSQL文を出力するために使用している。
Create
Createメソッドを使用する。
宣言した構造体をポインタを用いて初期化して、挿入したい値を記載する。
&
を使用せずに実行すると以下のエラーになる。
panic: reflect: reflect.Value.Set using unaddressable value
1レコードの挿入
db.Create(&Data1{Title: "title1", Content: "content1"})
発行されるSQL
INSERT INTO `data1` (`created_at`,`updated_at`,`deleted_at`,`title`,`content`) VALUES ('2022-08-06 12:52:12.414','2022-08-06 12:52:12.414',NULL,'title1','content1')
複数レコードの挿入
構造体初期化時に配列を使用することで複数レコードの挿入が可能。
var multi_create = []Data1{{Title: "title2", Content: "content2"}, {Title: "title3", Content: "content3"}, {Title: "title4", Content: "content3"}}
db.Debug().Create(&multi_create)
INSERT INTO `data1` (`created_at`,`updated_at`,`deleted_at`,`title`,`content`) VALUES ('2022-08-06 12:52:12.417','2022-08-06 12:52:12.417',NULL,'title2','content2'),('2022-08-06 12:52:12.417','2022-08-06 12:52:12.417',NULL,'title3','content3'),('2022-08-06 12:52:12.417','2022-08-06 12:52:12.417',NULL,'title4','content3')
その後のデーターベース
データーベースを確認すると意図した内容で登録されていることが確認できる。
Read
WHERE句の使用
db.Debug().First(&data1, 1)
SELECT * FROM `data1` WHERE `data1`.`id` = 1 AND `data1`.`deleted_at` IS NULL ORDER BY `data1`.`id` LIMIT 1
取得できた値
{{1 2022-08-06 12:52:12.414 +0900 JST 2022-08-06 12:52:12.414 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title1 content1}
// JSON変換時
{"ID":1,"CreatedAt":"2022-08-06T12:52:12.414+09:00","UpdatedAt":"2022-08-06T12:52:12.414+09:00","DeletedAt":null,"title":"title1","content":"content1"}
全レコードの取得
Findメソッド内の関数が配列でないと1レコードしか値を取得できないため、配列を使用して初期化しているdata1_arr
変数(構造体)を使用している。
db.Debug().Find(&data1_arr)
SELECT * FROM `data1` WHERE `data1`.`deleted_at` IS NULL
[{{1 2022-08-06 12:52:12.414 +0900 JST 2022-08-06 12:52:12.414 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title1 content1} {{2 2022-08-06 12:52:12.417 +0900 JST 2022-08-06 12:52:12.417 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title2 content2} {{3 2022-08-06 12:52:12.417 +0900 JST 2022-08-06 12:52:12.417 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title3 content3} {{4 2022-08-06 12:52:12.417 +0900 JST 2022-08-06 12:52:12.417 +0900 JST {0001-01-01 00:00:00 +0000 UTC false}} title4 content3}]
// JSON変換時
[{"ID":1,"CreatedAt":"2022-08-06T12:52:12.414+09:00","UpdatedAt":"2022-08-06T12:52:12.414+09:00","DeletedAt":null,"title":"title1","content":"content1"},{"ID":2,"CreatedAt":"2022-08-06T12:52:12.417+09:00","UpdatedAt":"2022-08-06T12:52:12.417+09:00","DeletedAt":null,"title":"title2","content":"content2"},{"ID":3,"CreatedAt":"2022-08-06T12:52:12.417+09:00","UpdatedAt":"2022-08-06T12:52:12.417+09:00","DeletedAt":null,"title":"title3","content":"content3"},{"ID":4,"CreatedAt":"2022-08-06T12:52:12.417+09:00","UpdatedAt":"2022-08-06T12:52:12.417+09:00","DeletedAt":null,"title":"title4","content":"content3"}]
Update
単一カラム
db.Model(&Data1{}).Where("id = ?", 1).Update("Title", "titleUpdate")
UPDATE `data1` SET `title`='titleUpdate',`updated_at`='2022-08-06 14:48:57.211' WHERE id = 1 AND `data1`.`deleted_at` IS NULL
複数カラム
db.Model(&data1).Where("id = ?", 1).Updates(Data1{Title: "titleMultUpdate", Content: "ContentMultUpdate"})
UPDATE `data1` SET `updated_at`='2022-08-06 14:48:57.217',`title`='titleMultUpdate',`content`='ContentMultUpdate' WHERE id = 2 AND `data1`.`deleted_at` IS NULL
変更後
エラー
GORMのリファレンスに記載されているが、全レコードの更新を行おうとするとエラーが出る。
Update文ではWHERE句を使用するべきである。
db.Model(&data1).Update("title1", "titleUpdate")
// error
WHERE conditions required
Delete
今回は論理削除を取り扱う。
ID1番のレコードを削除する。
db.Debug().Delete(&data1, 1)
UPDATE `data1` SET `deleted_at`='2022-08-06 14:59:27.779' WHERE `data1`.`id` = 1 AND `data1`.`deleted_at` IS NULL
poiter
ポインタがないとエラーになる
panic: reflect: reflect.Value.Set using unaddressable value
結果
ID1
のレコードのdeleted_at
カラムに値が挿入されていることが分かる。