15
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

OPENLOGIAdvent Calendar 2020

Day 19

GORMがv2になっていたので、変更点を調べてみる

Last updated at Posted at 2020-12-18

はじめに

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.iohttps://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 という型で定義する必要があります。

v1
type Example struct {
...

  DeletedAt *time.Time
}
v2
type Example struct {
...

  Deleted gorm.DeletedAt
}

Hooks

実際にSQLが発行される前後のHook処理もインターフェースの条件が変更されています。

v1

DOMに下記の名前のメソッドを実装することで処理を呼ぶことができます。

BeforeSave
BeforeCreate
AfterCreate
AfterSave

v2

メソッド名に変更はありませんが、HooksThe type of hook methods should be func(*gorm.DB) error 記述にあるように
それぞれのメソッドの引数に *gorm.DB を渡す必要があります。
メソッドの型が異なると、実際の処理時には実行されないため注意が必要です。

RecordNotFound

Selectを発行して該当レコードがない場合に、db.RecordNotFound() メソッドで判定していましたが、
当該メソッドがなくなりました。errors.Is()を使用して、判定を行う必要があります。

v1
db = db.First(entity)
if db.RecordNotFound() {
  ...
}
v2
db = db.First(entity)
if errors.Is(db.Error, gorm.ErrRecordNotFound) {
   ...
}

ログ出力

デバッグログの出力設定が変わりました。

v1

LogModeをtrueに設定するだけで、SQLがログ出力されます。

v1
db.LogMode(true)

v2

Logger を設定する必要があります。
新しくGORM用のLoggerが提供されており、出力レベルが変更できるようになりました。
レベルをInfo にすることで、SQLのログ出力が行われます。

logger/logger.go
const (
	Silent LogLevel = iota + 1
	Error
	Warn
	Info
)
v2
import (
  "gorm.io/gorm"
  "gorm.io/gorm/logger"
)

...
db.Logger = db.Logger.LogMode(logger.Info)
...

DB()

地味な変更ですが、v1の時には、 *gorm.DB の DB()メソッドを呼ぶことで、*sql.DB だけを取得することができましたが、
v2においては、errorも返すようになりました。

v1
db.DB().SetMaxIdleConns(10)
v2
if sqlDb, err := db.DB(); err != nil {
  panic(err)
} else {
  sqlDB.SetMaxIdleConns(10)
}

Close

v1においては*gorm.DBにCloseメソッドがありましたが、v2ではなくなりました。
v2では、*sql.DBを取得してCloseを実行する必要があります。

v1
 db.Close()
v2
if sqlDB, err := db.DB(); err != nil {
  ...
} else {
  if err := sqlDB.Close(); err != nil {
     ...
  }
}

まとめ

上にあげた点だけではなく、マイグレーションや、バッチ更新など、かなり機能が追加されています。
これから新しく作るプロダクトにおいては、最新版を使うことで、他のライブラリを探す手間がはぶけるというところでしょうか。
すでに動いているものを急いで更新するメリットはあまり感じません。
それでもバージョンアップを行う場合には、単にビルドが通ればいいというわけではなく、
ビルド時のエラーがでない変更も多いため、事前の動作確認を確実に行う必要があります。

15
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?