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
, CONSTRAINTfk_stud_schid
FOREIGN KEY (SchId
) REFERENCESschool
(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 外键关联限制,通过业务去控制/验证关联数据,实际上现在很多公司都是这样子做,这样子 更加可控
版权声明
未经授权,禁止转载本文章。
如需转载请保留原文链接并注明出处。即视为默认获得授权。
未保留原文链接未注明出处或删除链接将视为侵权,必追究法律责任!