はじめに
golangでプロトタイプを作成していて、いつも通り GORM
を利用しようとした際、どうせなら最新版でと思ったところ、 大きく変わっていました。
詳細は、v2のリリースノートを見てもらうのが一番ですが、変更点も多いため、単純にバージョンアップする際にひっかかりそうなところを調べてみました。
インストール
この記事の段階での最新バージョンは、1.20.8
になりますが、
1.20系にバージョン番号が上がると、インストールする際のパスが変更されます。
いままでは
go get -u github.com/jinzhu/gorm
となっていましたが、 v2になって
go get -u gorm.io/gorm
ドキュメントも https://v1.gorm.io と https://gorm.io/ に分かれています。
Open
初期化する際の関数も引数が変更されています。
v1
func Open(dialect string, args ...interface{}) (db *DB, err error)
第1引数が、"mysql"
や"postgres"
といった接続するRDBMSの種類を文字列で指定し、第2引数に接続文字列を渡します。
また、必要なDriverパッケージをブランク識別子を使用してインポートする必要があります。
import (
"github.com/jinzhu/gorm"
_ "github.com/go-sql-driver/mysql"
)
func main() {
db, err := gorm.Open("mysql", "test:test@/testdb")
...
}
v2
func Open(dialector Dialector, config *Config) (db *DB, err error)
第1引数に gorm.Dialector
という型で渡すように変更されています。
こちらは接続するRDBMSの種類に応じて、gorm用のDriverを初期化して渡す必要があります。
v2の場合は、ブランク識別子は不要になります。
また、第2引数のConfigでいろいろと細かい設定や機能が追加されていますが、今回は省略します。
import (
"gorm.io/driver/mysql"
"gorm.io/gorm"
)
func main() {
db, err := gorm.Open(mysql.Open("test:test@/testdb"), &gorm.Config{})
...
}
DeletedAt
論理削除をしたい場合、v1では DeletedAt
フィールドを *time.Timeで用意していましたが、
v2では、フィールド名ではなく、gorm.DeletedAt
という型で定義する必要があります。
type Example struct {
...
DeletedAt *time.Time
}
type Example struct {
...
Deleted gorm.DeletedAt
}
Hooks
実際にSQLが発行される前後のHook処理もインターフェースの条件が変更されています。
v1
DOMに下記の名前のメソッドを実装することで処理を呼ぶことができます。
BeforeSave
BeforeCreate
AfterCreate
AfterSave
v2
メソッド名に変更はありませんが、Hooks の The type of hook methods should be func(*gorm.DB) error
記述にあるように
それぞれのメソッドの引数に *gorm.DB
を渡す必要があります。
メソッドの型が異なると、実際の処理時には実行されないため注意が必要です。
RecordNotFound
Selectを発行して該当レコードがない場合に、db.RecordNotFound() メソッドで判定していましたが、
当該メソッドがなくなりました。errors.Is()を使用して、判定を行う必要があります。
db = db.First(entity)
if db.RecordNotFound() {
...
}
db = db.First(entity)
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
...
}
ログ出力
デバッグログの出力設定が変わりました。
v1
LogModeをtrueに設定するだけで、SQLがログ出力されます。
db.LogMode(true)
v2
Logger を設定する必要があります。
新しくGORM用のLoggerが提供されており、出力レベルが変更できるようになりました。
レベルをInfo
にすることで、SQLのログ出力が行われます。
const (
Silent LogLevel = iota + 1
Error
Warn
Info
)
import (
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
...
db.Logger = db.Logger.LogMode(logger.Info)
...
DB()
地味な変更ですが、v1の時には、 *gorm.DB の DB()メソッドを呼ぶことで、*sql.DB だけを取得することができましたが、
v2においては、errorも返すようになりました。
db.DB().SetMaxIdleConns(10)
if sqlDb, err := db.DB(); err != nil {
panic(err)
} else {
sqlDB.SetMaxIdleConns(10)
}
Close
v1においては*gorm.DBにCloseメソッドがありましたが、v2ではなくなりました。
v2では、*sql.DBを取得してCloseを実行する必要があります。
db.Close()
if sqlDB, err := db.DB(); err != nil {
...
} else {
if err := sqlDB.Close(); err != nil {
...
}
}
まとめ
上にあげた点だけではなく、マイグレーションや、バッチ更新など、かなり機能が追加されています。
これから新しく作るプロダクトにおいては、最新版を使うことで、他のライブラリを探す手間がはぶけるというところでしょうか。
すでに動いているものを急いで更新するメリットはあまり感じません。
それでもバージョンアップを行う場合には、単にビルドが通ればいいというわけではなく、
ビルド時のエラーがでない変更も多いため、事前の動作確認を確実に行う必要があります。