目录

Go踩过的坑之gorm外键关联字段无法插入

问题

在使用 go gorm 框架插入记录时,由于表模型带有关联外键,在出现外键为 null 值或不存在时会出现报错

模型如下

type School struct{
     SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;not null;primary_key;AUTO_INCREMENT;"`
    Name      string  `json:"Name"        gorm:"column:Name;type:varchar;size:500;not null;"`
}
type Stu struct{
    StuId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;not null;primary_key;AUTO_INCREMENT;"`
    Name      string  `json:"Name"        gorm:"column:Name;type:varchar;size:500;not null;"`
    SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;"`
}

Stu 数据库表存在外键关联 SchId

插入代码

func main() {
    addModel := model.Stu{
        Name:   "fiveyoboy",
    }
    err:=dao.insert(&addModel)
    if err.Error!=nil{
        fmt.Println(err)
    }
}

报错:

Error 1452: Cannot add or update a child row: a foreign key constraint fails (ew_nfdas.stu, CONSTRAINT fk_stud_schid FOREIGN KEY (SchId) REFERENCES school (SchId) ON DELETE SET NULL ON UPDATE SET NULL)

原因

通过报错分析:

Error 1452: Cannot add or update a child row: a foreign key constraint fails (ew_nfdas.stu, CONSTRAINT fk_stud_schid FOREIGN KEY (SchId) REFERENCES school (SchId) ON DELETE SET NULL ON UPDATE SET NULL)

大概意思是:在插入stu表时SchId字段的值在关联表School中无法找到

因为插入 stu 时没有设置 SchId 字段的值,所以会默认值为 0

# 以上代码实际执行的 sql 语句如下
INSERT INTO `stu` (`Name`,`SchId`) VALUES ('fiveyoboy',0)

会添加记录 SchId 的值为 0

但是由于表设置了外键关联,SchId = 0 在 School 表不存在记录,因此就会报错

解决

(一)方式一(推荐)

如果上面的可以知道插入语句为:

INSERT INTO `stu` (`Name`,`SchId`) VALUES ('fiveyoboy',0)

那么只要插入语句中不要插入 SchId 的值就不会报错,最终记录 SchId 会是 null

那么只需要在 SchId 字段上添加一个 gorm tag default:‘galeone’ 即可

代码如下

type Stu struct{
    StuId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;not null;primary_key;AUTO_INCREMENT;"`
    Name      string  `json:"Name"        gorm:"column:Name;type:varchar;size:500;not null;"`
    SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;default:galeone"`
}

default:galeone 表示默认值为缺省,也就是在插入时,如果给字段是零值,则生成插入语句

结果就会是

INSERT INTO stu (Name) VALUES (‘fiveyoboy’)

(二)方式二(推荐)

使用 null 值插入

前面方式一是直接不添加插入字段,

方式二是修改默认值为 null,也就是插入字段的默认值不再是 0,而是 null 值,这样子也是可以的

type Stu struct{
    StuId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;not null;primary_key;AUTO_INCREMENT;"`
    Name      string  `json:"Name"        gorm:"column:Name;type:varchar;size:500;not null;"`
    SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;default:null"`
}

default:null

表示但是该字段未设置值时,插入的默认值为 null

结果就会是

INSERT INTO stu (Name,SchId) VALUES (‘fiveyoboy’,null)

这样子也是不会报错的

(三)方式三

这种是基于业务需求来定,比如某种场景下规定,如果 stu 没有指定 School,那么就给个默认 School

比如先在 Shool 表添加一个 id=1 的记录

然后修改插入时 SchId 的默认值为 1

代码如下

type Stu struct{
    StuId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;not null;primary_key;AUTO_INCREMENT;"`
    Name      string  `json:"Name"        gorm:"column:Name;type:varchar;size:500;not null;"`
    SchId    int     `json:"SchId"      gorm:"column:SchId;type:int;size:11;default:1"`
}

这样子但插入 Stu 时没有指定 SchId 值时,就会默认插入该值=1

INSERT INTO stu (Name,SchId) VALUES (‘fiveyoboy’,1)

总结

不管是方式一、方式二、方式三,都是大同小异,都是通过设置字段的默认值来实现,无非是默认值是 null,还是缺省、还是自定义存在的记录

当然还有一种方式就是去掉表的关联设置,去掉 Stu 表的 SchId 外键关联限制,通过业务去控制/验证关联数据,实际上现在很多公司都是这样子做,这样子 更加可控

版权声明

未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!

本文原文链接: https://fiveyoboy.com/articles/go-gorm-err-1/

备用原文链接: https://blog.fiveyoboy.com/articles/go-gorm-err-1/