目录

文章目录

  • 目录
  • 前言
  • 实体完整性(主键约束)
  • 用户定义完整性(非空约束、唯一约束、检查约束和默认值)
  • 参照完整性(外键约束)
  • 关联关系
    • 一对一、一对多关联
    • 多对多关联
    • 示例

前言

本文基于 PostgreSQL 和 GORM 1.9 版本。GORM v2 对下文中的不足进行了优化。

全新的 Migrator:允许为关系创建数据库外键,更智能的 AutoMigrate,支持约束、检查器,增强索引支持。

实体完整性(主键约束)

每个关系(表)至少存在一个主键(Primary Key),主键值必须唯一,且不允许为 NULL。

type Product struct {gorm.ModelCode  string `gorm:"primary_key"`Price    uint...
}

grom.Model 是 GORM 内建的 Struct,用于实现软删除,如下:

type Model struct {ID uint `gorm:"primary_key"`CreatedAt time.TimeUpdatedAt time.TimeDeletedAt *time.Time `sql:"index"`
}

可见,Model Struct Product 具有两个 primary_key:CONSTRAINT products_pkey PRIMARY KEY (code, id)

因此,GORM 实现了完全的实体完整性支持,即可以支持字段主键,也可以支持联合主键。

用户定义完整性(非空约束、唯一约束、检查约束和默认值)

又称为域完整性。指数据库表中的列必须满足某种特定的数据类型或约束,包括:字段类型、值域、小数位数、CHECK、FOREIGN KEY 约束和 DEFAULT、 NOT NULL。它们有的定义在字段上,有的定义在表上。例如:FOREIGN KEY 约束在 PostgresSQL 中,就是在表级别定义的;而字段类型、长度、小数位数就是在字段上定义的。

GORM 通过 Struct Tag 来支持用户定义完整性:

`gorm:"xxx"`

xxx 可以使用 type、size、precision、not null、default 等 Tags 类型。

其中 Check 约束需要使用到 sql tag,例如:

UserID uint `sql:"type:integer check(code!='')"`

它会被定义到表上:

ALTER TABLE public.productsADD CONSTRAINT products CHECK (code <> ''::text);

参照完整性(外键约束)

通过定义 Model Struct 创建了一个 products belongs to user 的 Belong to 一对一关系。

// 主表
type User struct {gorm.ModelCode string `gorm:"primary_key"`Name string
}// 从表
type Product struct {gorm.ModelCode     string `gorm:"primary_key"`Price    uintUserID  uintUser    User
}

AutoMigrate 的时候会执行 SQL 语句创建 products(从)表:

CREATE TABLE "products"
("code" text,"price" integer,"user_id" integer,"id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone , PRIMARY KEY ("id")
)

可见,GORM 没有添加任何约束。按照 GORM 的文档,这就是 belongs to 的标准定义,它不添加外键约束

尝试显式的指定 foreignkey Tag:

type Product struct {Code    string  `gorm:"primary_key"`Price   uintUserID  uintUser    User    `gorm:"foreignkey:UserID;association_foreignkey:ID"`gorm.Model
}type User struct {Code     string `gorm:"primary_key"`Name     stringgorm.Model
}

执行的 SQL 是:

CREATE TABLE "products"
("code" text,"price" integer,"user_id" integer,"id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone , PRIMARY KEY ("id")
)

可见,GORM 还是没有添加任何外键约束。

因此,可以确定 GORM 的 foreignkey、association_foreignkey tag 并不会添加外键约束

尝试显式指定 GORM 的 sql tag 来添加外键约束:

type Product struct {Code    string  `gorm:"primary_key"`Price   uintUserID  uint    `sql:"type:integer REFERENCES users(id) on update no action on delete no action"` // no action 模式外键约束User   User    `gorm:"foreignkey:UserID;association_foreignkey:ID"`gorm.Model
}type User struct {Code string `gorm:"primary_key"`Name stringgorm.Model
}

执行的 SQL 语句:

CREATE TABLE "products"
("code" text,"price" integer,"user_id" integer REFERENCES users(id) on update no action on delete no action,"id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone , PRIMARY KEY ("id")
)

可见,从表的外键约束被定义了。也就是说 GORM 1.9 版本如果希望创建表时定义外键(References,参照),那么就需要使用到 sql tag

注意,sql tag 与 gorm tag 有区别,前者需要硬编码相应的数据库 TableName和 ColumnName,而后者就只需要你使用结构体和其成员名即可。

除了 no action 模式之外,sql tag 同样支持:

  • CASCADE(级联)约束方式
UserID uint `sql:"type:integer REFERENCES users(id) on update cascade on delete cascade"`
  • SET NULL(设空)约束方式
  • RESTRICT(禁止)方式:在 PostgreSQl 中与 no action 具有类似的语义。

另外,使用 sql tag 还可以使用 constraint xxx 自定义外键约束名,即引用名称:

UserID uint `sql:"type:integer constraint ref_name REFERENCES users(id) on update no action on delete no action"`

同样的,GORM 也支持联合外键,这时候就需要使用到 GORM 提供的接口了:

db.Model(&Product{}).AddForeignKey( "user_id,user_code", "users(id,code)", "no action", "no action")

执行 SQL 语句:

CONSTRAINT products_user_id_user_code_users_id_code_foreign FOREIGN KEY (user_code, user_id)REFERENCES public.users (code, id) MATCH SIMPLE ON UPDATE NO ACTION ON DELETE NO ACTION

关联关系

一对一、一对多关联,多对多关联不属于完整性范畴,即:RDBMS 不会自动完成数据完整性检查,包括引用的可用性检查,数据的一致性检查等,这些工作都需要有应用层业务逻辑来实现。所以,在逻辑代码中也不需要实现任何完整性约束定义,因此 Model Struct 里也无需添加额外的约束。

一对一、一对多关联

type User struct {gorm.ModelCode      string `gorm:"primary_key"`Name     stringProducts []Product
}type Product struct {gorm.ModelCode    string `gorm:"primary_key"`Price    uintUserID uint
}

这是典型的一对多定义,users 表无需添加约束字段,product 表也只需要添加 user_id 字段作为外键。这里可以省略,也可以显式的定义 gorm tag:foreignkey 或 association_foreignkey,例如:

type User struct {gorm.ModelCode      string     `gorm:"primary_key"`Name     stringProducts []Product  `gorm:"foreignkey:UserID"`
}

多对多关联

在关系型数据库中,多对多关系需要一张中间表。

type User struct {gorm.ModelCode      string     `gorm:"primary_key"`Name     stringProducts []Product  `gorm:"many2many:user_language"`
}type Product struct {gorm.ModelCode    string `gorm:"primary_key"`Price    uint
}

会执行 SQL:

CREATE TABLE "user_language"
("user_id" integer,"product_id" integer,PRIMARY KEY ("user_id","product_id")
)

GORM 会自动创建一张 user_language 连接表(Join Table)。products、users 表的主键,被联合作为 user_language 表的主键。GORM 也会自动的完成 user_id 和 product_id 作为外键的关联。但正如上述所言,外键约束是不会自动完成的。

示例

// 文章表
type Article struct {ID             int         `json:"id"`Title        string      `json:"title"`CategoryId    int         `json:"category_id"`Category    Category    `json:"category";gorm:"foreignkey:CategoryID"` // 一对多关系Tag        []Tag       `gorm:"many2many:article_tag" json:"tag"` // 多对多关系
}// 文章_标签多对多中间表
// 默认的,article_id 字段对应 article 表 id,tag_id 字段对应 tag 表 id
type ArticleTag struct {ID          int     `json:"id"`ArticleId    string  `json:"article_id"`TagId        string  `json:"tag_id"`
}// 标签表
type Tag struct {ID         int     `json:"id" `TagName string  `json:"tag_name"`
}// 分类表
type Category struct {ID             int    `json:"id"`CategoryName string `json:"category_name"`Status          int    `json:"status"`
}
  • 查一列:
func (a *Article) ListArticle(title string) (Article, error) {query := database.GormPoolvar article Articlequery.Where("title like ?", "%"+title+"%").First(&article)fmt.Println(article)err := query.Model(&article).Related(&article.Category).Related(&article.Tag, "tag").Find(&article).Errorif err != nil && err != gorm.ErrRecordNotFound {return article, nil}return article, err
}

通过 Related 方法,可以查找 belongs to、has one、has many、many to many 关系。

查找一列时,首先是需要先把特定的一条 Article 查询到,然后根据 Article 定义中指定的 CategoryID 去查找 Category 和 Tag。

  • 查多列表:
func (a *Article) ListArticle(title string) (articles []Article, err error) {query := database.GormPoolerr = query.Model(articles).Where("title like ?", "%"+title+"%").Preload("Category").Preload("Tag").Find(&articles).Errorif err != nil && err != gorm.ErrRecordNotFound {return}return
}

查看多列时,使用 Preload 方法可以完成多表关系的预加载,然后再自动执行选择(WHERE)运算。

Go 语言编程 — gorm 的数据完整性约束相关推荐

  1. c语言一元线性回归方程程序,C语言编程对实验数据进行一元线性回归处理

    1997年第3期 云南化工 55 计算机应用 C语言编程对实验数据进行一元线性回归处理 杨继红 尹家元 沈 勇 (云南大学化学系 昆明650091) 摘 要 用目前最有发展前景的C语言编程处理分析实验 ...

  2. Go 语言编程 — gorm 数据库版本迁移

    目录 文章目录 目录 前言 AutoMigrate 示例 Migrator 接口(DDL 操作方法) 表操作 列操作 约束操作 索引操作 数据库版本控制 参考文档 前言 本文示例为 GORM V2.0 ...

  3. Go 语言编程 — gorm ORM 框架

    目录 文章目录 目录 实现一个关系型数据库应用程序需要做什么? GORM 连接数据库 表定义 Module Struct tags 表操作 db.HasTable 表是否存在 db.CreateTab ...

  4. Go 语言编程 — gormigrate GORM 的数据库迁移助手

    目录 文章目录 目录 前言 gormigrate 核心结构体 实现分析 版本定义 InitSchema Migration 版本记录(历史) 版本升级和回退 前言 GORM v2 gormigrate ...

  5. c语言编程物理实验,大学物理实验报告大全C语言编程在大学物理实验中处理数据的研究...

    大学物理实验报告大全C语言编程在大学物理实验中处理数据的研究 摘要 用C语言编程的方法处理比较复杂的实验数据,简捷准确且避免了传统方法的弊端,与用Excel处理数据的方法相比,其结果更符合误差理论. ...

  6. 【R语言编程基础】【课后习题答案】【全】

    文章目录 第1章 R语言概述 1.选择题 2.操作题 第2章 数据对象与数据读写 1.选择题 2.操作题 第3章 数据集基本处理 1.选择题 2.操作题 第4章 函数与控制流 1.选择题 2.操作题 ...

  7. Go语言编程笔记16:存储数据

    Go语言编程笔记16:存储数据 图源:wallpapercave.com 几乎任何程序都绕不开读写数据,只不过具体的数据存储介质和方式有所不同.本篇文章将从多种数据存储方式进行探讨各种存储方式如何实现 ...

  8. C 语言编程 — 数据类型转换

    目录 文章目录 目录 前文列表 数据类型转换 隐式(自动)类型转换 常用的算术转换 显式(强制)类型转换 字符串转换为数字类型:atoi.atol.atof 前文列表 <程序编译流程与 GCC ...

  9. 数据科学家们,请补齐你的短板,如何提升R语言编程能力

    前言 这个世界每天都在源源不断地生产数据,而人们尤其是商界往往希望从这些数据中获取到有价值的信息.而这一点也促使很多试图从数据中提取有用信息的数据科学家们(或被叫做数据分析师.数据挖掘者等等听起来不错 ...

最新文章

  1. NASA打算送机器蜜蜂去探索火星上的生命痕迹
  2. Exchange 数据库邮箱的修复
  3. linux控制台界面编程,控制台窗口界面的编程控制(二)
  4. 零食嘴----美食领域的美丽说
  5. Servlet和JSP中的文件上传示例
  6. 演变模型_开放组织的演变
  7. 一文带你了解数据中心大二层网络演进之路
  8. dfs.datanode.directoryscan.throttle.limit.ms.per.
  9. [iOS] 使用xib做为应用程序入口 with Code
  10. 世上最全计算机网络面试整理(附答案),不服来战!!
  11. springboot配置微信公众号获取openid
  12. python qt教程视频 下载_Qt基础课程视频教程 教学视频 百度网盘下载
  13. java 右对齐_字符串对齐器(左对齐、居中、右对齐)
  14. 使用 Packer 构建虚拟机镜像踩的坑
  15. Grammer -- 疑问句
  16. 透过上层div点击下层div
  17. 安卓更新下载apk 并安装
  18. 电信中兴F460光猫破解续
  19. Mac平台epub阅读器推荐
  20. 解决Hexo博客引用网络图片无法显示的问题

热门文章

  1. iOS10 UI教程视图的中心位置
  2. linux中流设备_Linux设备驱动子系统终极弹
  3. gui的design 无界面_无蓝光不刺眼 海信阅读手机超长续航双11嗨不停_
  4. 陪孩子一起学python第二季_陪伴作文开头和结尾
  5. 智能假手与机器人融合可以灵活抓取物品
  6. 探索频道和谷歌联合制作七大洲人文VR视频,11月3日可收看
  7. “AI理论之父应该是哥德尔”,LSTM之父再抛惊人观点,网友:他有点走火入魔...
  8. 谷歌上线AI新玩法:随手乱涂鸦,一键变怪兽
  9. 小米做的这件事,捍卫了你的隐私
  10. 全球十大AI训练芯片大盘点:华为昇腾910是中国唯一入选