gormのドキュメントに記載されているWARNINGが怖かったので、サンプルコードを書いて動作の確認をしてみた。
WARNING When deleting a record, you need to ensure its primary field has value, and GORM will use the primary key to delete the record, if the primary key field is blank, GORM will delete all records for the model
検証コード
package main
import (
"github.com/jinzhu/gorm"
// mysql driver
_ "github.com/jinzhu/gorm/dialects/mysql"
)
// Animal primary_keyタグなし
type Animal struct {
ID string
}
// Bird primary_keyタグあり
type Bird struct {
ID string `gorm:"primary_key"`
}
// Fish IDとは異なる名前 かつ primary_keyタグなし
type Fish struct {
FishID string
}
// Fruit IDとは異なる名前 かつ primary_keyタグあり
type Fruit struct {
FruitID string `gorm:"primary_key"`
}
func main() {
db, _ := gorm.Open("mysql", "root@tcp(127.0.0.1:3306)/example?parseTime=true")
defer db.Close()
// 構造体に沿ったテーブルを作成
db.AutoMigrate(&Animal{}, &Bird{}, &Fish{}, &Fruit{})
// テストデータの用意
animal := &Animal{
ID: "001",
}
bird := &Bird{
ID: "001",
}
fish := &Fish{
FishID: "001",
}
fruit := &Fruit{
FruitID: "001",
}
db.Create(&animal)
db.Create(&bird)
db.Create(&fish)
db.Create(&fruit)
// テストデータの削除
db.Debug().Delete(&animal)
db.Debug().Delete(&bird)
db.Debug().Delete(&fish)
db.Debug().Delete(&fruit)
}
出力されるクエリ
DELETE FROM `animals` WHERE `animals`.`id` = '001'
DELETE FROM `birds` WHERE `birds`.`id` = '001'
DELETE FROM `fish`
DELETE FROM `fruits` WHERE `fruits`.`fruit_id` = '001'
まとめ
| カラム名 | プライマリーキータグ | 挙動 |
|---|---|---|
| id | ✕ | 対象IDのレコードが消える |
| id | ◯ | 対象IDのレコードが消える |
| xxx_id | ✕ | 全件吹っ飛ぶ |
| xxx_id | ◯ | 対象IDのレコードが消える |
id という名前のカラムのみ、 primary_keyタグを書かなくても内部でプライマリーキーとして扱ってくれるもよう。
タグを適切に書くというのはもちろんだけど、記載漏れでテーブル内のレコードが全件消えるリスクを考えると
db.Where("id = ?", animal.ID).Delete(&Animal{})
とWhere句を明示的に書いたほうが事故防止になって良さそう。