前提
gorm v2.0 で確認しています。
"gorm.io/gorm"
User 構造体は以下のものを使用しています。
type User struct {
ID int `gorm:"column:id;primary_key:yes"`
Email string `gorm:"column:email"`
Age int `gorm:"column:age"`
IsAdmin bool `gorm:"column:is_admin"`
CreatedAt time.Time `gorm:"column:created_at"`
UpdatedAt time.Time `gorm:"column:updated_at"`
}
Where
構造体を利用した書き方ですとフィールドがポインタ型でない場合ゼロ値("", 0, false)は検索できないため、事故を防ぐならベタで書くのが一番安全かと思います。
ただ、DB の構造体のフィールドをすべてポインタ型で宣言するようなルールになっている場合は構造体を利用した書き方で統一しても良いかと思います。
db.Where(User{Email: "example", Age: 10, IsAdmin: true}).Find(&user)
// => SELECT * FROM `users` WHERE `users`.`email` = "example" AND `users`.`age` = 10 AND `users`.`is_admin` = true;
db.Where(User{Email: "", Age: 0, IsAdmin: false}).Find(&user)
// => SELECT * FROM `users`;
db.Debug().Where("email = ?", "").Where("age = ?", 0).Where("is_admin", false).Find(&user)
// => SELECT * FROM `users` WHERE email = "" AND age = 0 AND `is_admin` = false;
Update
v1 では Where 句と同様に更新するフィールドがポインタ型でない場合はゼロ値の更新はできませんでした。
db.Where("id = ?", 1).Updates(User{Email: "", Age: 0, IsAdmin: false})
// => UPDATE `users` SET `updated_at`="2020-09-08 17:26:26.386" WHERE id = 1;
db.Where("id = ?", 1).Updates(User{Email: "example", Age: 10, IsAdmin: true})
// => UPDATE `users` SET `email`="example",`age`=10,`is_admin`=true,`updated_at`="2020-09-08 17:25:07.501" WHERE id = 1;
しかし、v2 で更新するカラムを明示的に選択した状態だとゼロ値でも更新することが出来るようになりました。
db.Select("is_admin").Where("id = ?", 1).Updates(User{Email: "", Age: 0, IsAdmin: false})
// => UPDATE `users` SET `is_admin`=false WHERE id = 1;
Save
save はゼロ値に関わらず構造体に設定してる値を INSERT・UPDATE します
db.Debug().Save(&user)
// => INSERT INTO `users` (`email`,`age`,`is_admin`,`created_at`,`updated_at`) VALUES ("",0,false,"2020-09-08 08:01:09","2020-09-08 13:34:23");
// => UPDATE `users` SET `email`="",`age`=0,`is_admin`=false,`created_at`="2020-09-08 08:01:09",`updated_at`="2020-09-08 22:34:22.664" WHERE `id` = 1;
Delete
delete は特にゼロ値は関係ありませんので割愛。
オマケ
v2からUpdateとDeleteに条件文が必須になりましたので、全件更新・削除の事故がなくなりました。
primary_key:yes
つけ忘れて全件削除事故が起きた後にO/Rの仕様をしって驚愕したのはいい思い出です。