博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
go-xorm使用外键报错(Cannot add or update a child row: a foreign key constraint fails)
阅读量:5936 次
发布时间:2019-06-19

本文共 3649 字,大约阅读时间需要 12 分钟。

hot3.png

问题描述

使用mysql会经常遇到要使用外键的场景,go-xorm 作为一个orm的框架,在数据映射上使用非常方便,但在增添数据是经常碰到报错:

Cannot add or update a child row: a foreign key constraint fails

情不知所起

明明直接在数据库中插数据并没有报错,为什么用代码跑就出问题了?

报错原因

以上报错信息,英文的主要意思时外键约束未被满足,无法添加数据

具体原因插入的数据用外键的id在原表中不存在。

瞎编的案例

一个不严谨的业务场景

假设一个楼房有多个邮箱可以接受邮件,匿名邮件只有收件地址没有寄件地址,但每个楼房都有一个固定的邮递小哥负责将本楼房发出的邮件送到目的地,要统计楼房之间的通信情况需要三个表

mysql initail script

create table if no exists `buildings`(    `id` int(11) unsigned not null auto_inrement,    `addr` varchar(64) not null unique,    primary key(`id`))ENGINE=InnoDBcreate table if no exists `mailboxes`(    `id` int(11) unsigned not null auto_inrement,    `number` int(11) not null,    `building_id` int(11) not null,    `username` varchar(16),    primary key(`id`),    unique key `building_mailbox` (`number`, `building_id`),    constraint `mail_address` foreign key (`building_id`) refernces `buildings`(`id`) on delete cascade)ENGINE=InnoDBcreate table if no exists `links`(    `id` int(11) unsigned not null auto_inrement,    `mialbox_id` int(11) not null,    `building_id` int(11) not null,    primary key(`id`),    unique key `mail_link` (`mialbox_id`, `building_id`),    constraint `mailbox_link` foreign key (`building_id`) refernces `buildings`(`id`) on delete cascade,    constraint `building_link` foreign key (`mialbox_id`) refernces `mailboxes`(`id`) on delete cascade)ENGINE=InnoDB

go-xorm models

需要三个model,两个辅助model

主要model

type Building struct{    ID int64 `xorm:"pk autoincr notnull 'id'"`    Addr string `xorm:"varchar(64) nutnull unique"`}type Mailbox struct{    ···}type Link struct{    ···}

ps:使用vscode时,编辑器会建议将字段‘Id’改为‘ID’,但字段‘ID’对应数据库的字段会变成‘i_d’。所以为了强迫症舒服,必须在后面的xorm里面标注在数据库对于的字段,即上文中的‘id’

辅助model

type BuildingMailbox struct{    Building `xorm:"extends"`    Mailbox `xorm:"extends"`}type BuildingMailboxLink struct{}

Insert

func InsertLink(engine *xorm.Engine,box Mailbox,building Building) (l Link,err error){    l.MailboxID = box.ID    l.BuildingID = building.ID    _,err = engine.Table("links").Insert(&l)    if err != nil{        return fmt.Errorf("InsertLink:%v",err)    }    return nil}

错误原因

我遇到,或者说我犯过的错误有两种

using update

场景描述

func UpdateMailboxUsername(engine *xorm.Engine,id int64,name string) (box Mailbox,err error){    box.Username = name    _,err = engine.Table("mailboxes").ID(id).Update(box)    return}

使用上述代码更新数据库不会有任何问题。问题出在以下情况

box,err := UpdateMailboxUsername(e,id,"xorm")if err !=nil{    ···deal with the error···}link,has,err := GetLinkByBoxAndBuilding(e,box,building)if err !=nil{    ···deal with the error···}if !has{    link,err = InsertLink(e,box,building)}

这个时候InsertLink就会报以上的错。额且错误并不是由于InsertLink。

错误解释

Update方法可以接受以下两种情况

_,err = engine.Table("mailboxes").ID(id).Update(box)

_,err = engine.Table("mailboxes").ID(id).Update(&box)

但两种情况都不会修改box的ID值。

ps:使用 Insert(&box) 会在box中注入保存后的id值

内联查询结果映射

使用内联查询

func GetMailboxByAddrAndNum(e *xorm.Engine,addr string,num int64) (b BuildingMailbox,has bool,err error){    has,err = engine.Table("mailboxes").Select("mailboxes.*, buildings.*").        Join("INNER","buildings","mailboxes.building_id = buildings.id").        Where("mailboxed.number = ?",num).And("buidings.addr = ?",addr).Get(&b)    if err !=nil{        err = fmt.Errorf("GetMailboxByAddrAndNum:%v",err)    }    return}

以上函数能够得到结果,通过使用b.Mailboxb.Building,能够直接使用两个对象,而且从数值上看好像没错,除了一样——id

进过和数据库仔细对比会发现,只有id字段会与数据库记录的不相同。

错误原因

BuildingMailbox解析出错

在上述的

···Select("mailboxes.*, buildings.*")···

BuildingMailbox*定义中的顺序不一致。其他字段名称不同解析不会出现错误。但由于mailbox和building都有id字段,在解析式如果辅助结构体中定义的与数据就可能出现因为顺序不同而导致解析时出现id字段交换的情况。

小结

本文总结了笔者使用xorm的外键时犯过的错误。第一种错误是因为对go-xorm包不够熟悉,一段时间后自然就可以避免;第二种则要隐蔽得多,需要多多注意。

转载于:https://my.oschina.net/u/3703365/blog/1817543

你可能感兴趣的文章
Spring 定时任务实现 以及无法正常执行分析
查看>>
Linux基础(11)文本处理三剑客之sed
查看>>
bash命令行快捷键整理
查看>>
Zabbix3.2.6之通过JMX监控Tomcat
查看>>
2013美赛建模算法关键词
查看>>
Android-Parcelable理解与使用(对象序列化)
查看>>
数据结构----图(邻接表用法)
查看>>
批量扫描雏形之在Java中调用nmap进行主机探测
查看>>
我的友情链接
查看>>
SVN命令详解
查看>>
Windows的资源监视器
查看>>
Android图形解锁的绘制
查看>>
UML基础系列:类图
查看>>
学习日志---树回归(回归树,模型树)
查看>>
Gene6_FTP_Server_高级配置
查看>>
centos 7编译安装nginx
查看>>
【学神】1-15 linux启动及常见故障的排除
查看>>
Android SDK 在线更新镜像服务器资源
查看>>
重新定义工作站的“边界”
查看>>
第三方推送已死
查看>>