一般的にCRUDする分には、Modelメソッドに値型の構造体を渡しても動作はします。
if err := db.Debug().
Model(User{}).
Where("id = ?", 1).
Updates(User{Age: 30}).Error; err != nil {
fmt.Println("error:", err)
}
発生するエラー
しかし、Hooksを設定している状態で、Modelメソッドに値型の構造体を渡すと、以下のようなエラーが出力されます。
invalid value, should be pointer to struct or slice
Hooksとは
特定のテーブルに対して作成、取得、更新、削除の操作を行う前後に自動的に呼び出される関数のことです。
参考: https://gorm.io/ja_JP/docs/hooks.html
エラーが発生するコード例
func dbInit() *gorm.DB {
dsn := "root:@tcp(127.0.0.1:3306)/verify_db?charset=utf8mb4&parseTime=True&loc=Local"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
if err != nil {
fmt.Println("gorm open error:", err)
}
return db
}
type User struct {
ID uint
Name string
Email *string
Age uint8
Birthday *time.Time `gorm:"type:date"`
MemberNumber *string
ActivatedAt *time.Time
CreatedAt time.Time
UpdatedAt time.Time
}
func (u *User) BeforeSave(tx *gorm.DB) (err error) {
fmt.Println("BeforeSave run")
return
}
func main() {
db := dbInit()
if err := db.Debug().
Model(User{}). // 値型の構造体だとエラー
Where("id = ?", 1).
Update("age", 20).Error; err != nil {
fmt.Println("query error:", err)
}
}
このコードを実行すると、以下のようにエラーが発生します。
% go run main.go
query error: invalid value, should be pointer to struct or slice
User
構造体に定義したBeforeSave
メソッドが呼び出される前に、エラーで処理が中断されてしまいます。
解決方法
if err := db.Debug().
Model(&User{}). // ポインタ型の構造体に変更
Where("id = ?", 1).
Update("age", 20).Error; err != nil {
fmt.Println("query error:", err)
}
基本的には、Modelメソッドにはポインタ型の構造体を渡すようにしましょう。