Golang中使用Gorm结构体时遇到的问题

Golang中使用Gorm结构体时遇到的问题 我正在开发一个简单的鸟类繁殖应用程序,毕竟学习新东西总得找个有趣的项目,对吧?😊

到目前为止,一切运行得都很顺利。我可以添加、编辑和删除鸟类信息。但当我尝试添加字段来关联鸟类与其父母时,问题就出现了。难点在于,我们并不总是能同时拥有鸟类及其父母的信息。我目前能想到的最佳结构如下:

type Bird struct {
	gorm.Model
	RingNo   string `gorm:"not null"`
	Species  string `gorm:"not null"`
	Color    string `gorm:"not null"`
	■■■      string `gorm:"not null"`
	UserID   uint   `gorm:"not null"`
	User     User
	FatherID *uint
	Father   *Bird `gorm:"foreignKey:FatherID;default:SET NULL"`
	MotherID *uint
	Mother   *Bird `gorm:"foreignKey:MotherID;default:SET NULL"`
	Notes    []BirdNote `gorm:"foreignKey:BirdID"`
}

基本上,我想要实现的目标是让 FatherIDMotherID 可以为空。但无论我尝试什么方法,最终总是会遇到“违反键约束”的错误 😦


更多关于Golang中使用Gorm结构体时遇到的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html

3 回复

当我将所有内容都设置为字符串时,它可以工作。但那样我就必须手动填写父鸟ID和母鸟ID。在理想情况下,我可以通过下拉菜单将鸟与其父鸟和母鸟的脚环编号关联起来。(或者,如果我不知道父鸟和母鸟,就留空。)

// 代码部分保持原样,不翻译

更多关于Golang中使用Gorm结构体时遇到的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


我尚未使用过GORM,但搜索“gorm foreign key nullable”时,我找到了以下两个看起来很有希望的链接:

  1. postgresql - How to insert a null foreign key in gorm? - Stack Overflow
  2. How to create nullable foreign key in gorm/v2 · Issue #3188 · go-gorm/gorm · GitHub

我无法确定哪个解决方案效果最好,甚至不确定你是否需要进一步调整它们,但我希望它们能对你有所帮助。祝你顺利。:slight_smile:

在Golang中使用Gorm处理自引用外键时,确实需要特别注意外键约束。根据你的需求,正确的结构体定义应该如下:

type Bird struct {
	gorm.Model
	RingNo   string    `gorm:"not null"`
	Species  string    `gorm:"not null"`
	Color    string    `gorm:"not null"`
	UserID   uint      `gorm:"not null"`
	User     User
	FatherID *uint     `gorm:"default:null"`
	Father   *Bird     `gorm:"foreignKey:FatherID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
	MotherID *uint     `gorm:"default:null"`
	Mother   *Bird     `gorm:"foreignKey:MotherID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL;"`
	Notes    []BirdNote `gorm:"foreignKey:BirdID"`
}

关键点在于:

  1. FatherIDMotherID 使用 *uint 指针类型,配合 gorm:"default:null" 标签
  2. 在关联标签中明确指定外键约束行为:constraint:OnUpdate:CASCADE,OnDelete:SET NULL;

创建数据库迁移时,需要确保外键约束允许NULL值:

// 创建表时的SQL示例
db.Exec(`
CREATE TABLE birds (
    id SERIAL PRIMARY KEY,
    ring_no VARCHAR(255) NOT NULL,
    species VARCHAR(255) NOT NULL,
    color VARCHAR(255) NOT NULL,
    user_id INTEGER NOT NULL,
    father_id INTEGER,
    mother_id INTEGER,
    created_at TIMESTAMP,
    updated_at TIMESTAMP,
    deleted_at TIMESTAMP,
    FOREIGN KEY (father_id) REFERENCES birds(id) ON DELETE SET NULL,
    FOREIGN KEY (mother_id) REFERENCES birds(id) ON DELETE SET NULL
)
`)

插入数据时,对于没有父母的鸟类,将FatherID和MotherID设为nil:

// 创建没有父母的鸟
birdWithoutParents := Bird{
    RingNo:   "RING001",
    Species:  "Canary",
    Color:    "Yellow",
    UserID:   1,
    FatherID: nil,
    MotherID: nil,
}

// 创建有父母的鸟
fatherID := uint(1)
motherID := uint(2)
birdWithParents := Bird{
    RingNo:   "RING002",
    Species:  "Canary",
    Color:    "Yellow",
    UserID:   1,
    FatherID: &fatherID,
    MotherID: &motherID,
}

db.Create(&birdWithoutParents)
db.Create(&birdWithParents)

查询时使用Preload加载关联:

var bird Bird
db.Preload("Father").Preload("Mother").First(&bird, 1)

// 检查是否有父母
if bird.Father != nil {
    fmt.Printf("父亲: %s\n", bird.Father.RingNo)
}
if bird.Mother != nil {
    fmt.Printf("母亲: %s\n", bird.Mother.RingNo)
}

这样配置后,当删除父鸟时,子鸟的对应父ID会自动设置为NULL,不会违反外键约束。

回到顶部