はじめに
Go の O/R マッパーである GORM を使っていて、NULL でのアップデートに困っていたので記載しておきます。
環境
- Go 1.11.5
- jinzhu/gorm v1.9.2
結論
以下の User モデルを更新する例です。
type User struct {
ID uint `gorm:"primary_key"`
Age int
Name string
}
var user User
db.First(&user)
// 1 カラムの NULL アップデート
db.Model(&user).Update("name", gorm.Expr("NULL"))
// 実行 SQL : UPDATE `users` SET `name` = NULL WHERE `users`.`id` = '1'
// 複数カラムの NULL アップデート
db.Model(&user).Updates(map[string]interface{}{
"age": 18,
"name": gorm.Expr("NULL"),
})
// 実行 SQL : UPDATE `users` SET `age` = '18', `name` = NULL WHERE `users`.`id` = '1'
SQL Expression によるアップデートに使用する gorm.Expr
を使用して、直接 NULL
を渡すことで NULL でアップデートができることが分かりました。
試行錯誤
通常のアップデートであれば以下のように指定することで可能ですが、NULL でアップデートするには nil
を渡すなどで上手くいきませんでした。
db.Model(&user).Updates(User{Age: 18, Name: "hello"})
nil でのアップデート
NULL
を含んだ Insert 文を実行するには、対象のカラムをポインタにして nil
を渡すことで作成されます。
type User struct {
ID uint `gorm:"primary_key"`
Age int
- Name string
+ Name *string
}
実際に実行してみると、NULL
で作成されていることが分かります。
user := User{ID: 1, Age: 18, Name: nil}
db.Create(&user)
// 実行 SQL : INSERT INTO `users` (`id`,`age`,`name`) VALUES ('1','18',NULL)
では、同じ要領でアップデートでもポインタにしたカラムに nil
を渡してみると、無視されてしまうことが分かりました。
var user User
db.First(&user)
db.Model(&user).Updates(User{Age: 18, Name: nil})
// 実行 SQL : UPDATE `users` SET `age` = '18' WHERE `users`.`id` = '1'
GORM のドキュメントを見ると以下のように書いてあったので、構造体で実行すると無視されてしまうようです。
When query with struct, GORM will only query with those fields has non-zero value, that means if your field's value is 0, '', false or other zero values, it won't be used to build query conditions,