Go 语言编程 — gorm 的数据完整性约束

目录

文章目录

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

实体完整性(主键约束)

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

1type Product struct { 2 3 4 gorm.Model 5 Code string `gorm:"primary_key"` 6 Price uint 7 ... 8}

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

1type Model struct { 2 ID uint `gorm:"primary_key"` 3 CreatedAt time.Time 4 UpdatedAt time.Time 5 DeletedAt *time.Time `sql:"index"` 6}

可见,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!='')"`

它会被定义到表上:

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

参照完整性(外键约束)

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

1// 主表 2type User struct { 3 4 5 gorm.Model 6 Code string `gorm:"primary_key"` 7 Name string 8} 9 10// 从表 11type Product struct { 12 13 14 gorm.Model 15 Code string `gorm:"primary_key"` 16 Price uint 17 UserID uint 18 User User 19}

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

1CREATE TABLE "products" 2( 3 "code" text, 4 "price" integer, 5 "user_id" integer, 6 "id" serial, 7 "created_at" timestamp with time zone, 8 "updated_at" timestamp with time zone, 9 "deleted_at" timestamp with time zone , 10 PRIMARY KEY ("id") 11)

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

尝试显式的指定 foreignkey Tag:

1type Product struct { 2 3 4 Code string `gorm:"primary_key"` 5 Price uint 6 UserID uint 7 User User `gorm:"foreignkey:UserID;association_foreignkey:ID"` 8 gorm.Model 9} 10 11type User struct { 12 13 14 Code string `gorm:"primary_key"` 15 Name string 16 gorm.Model 17}

执行的 SQL 是:

1CREATE TABLE "products" 2( 3 "code" text, 4 "price" integer, 5 "user_id" integer, 6 "id" serial, 7 "created_at" timestamp with time zone, 8 "updated_at" timestamp with time zone, 9 "deleted_at" timestamp with time zone , 10 PRIMARY KEY ("id") 11)

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

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

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

1type Product struct { 2 3 4 Code string `gorm:"primary_key"` 5 Price uint 6 UserID uint `sql:"type:integer REFERENCES users(id) on update no action on delete no action"` // no action 模式外键约束 7 User User `gorm:"foreignkey:UserID;association_foreignkey:ID"` 8 gorm.Model 9} 10 11type User struct { 12 13 14 Code string `gorm:"primary_key"` 15 Name string 16 gorm.Model 17}

执行的 SQL 语句:

1CREATE TABLE "products" 2( 3 "code" text, 4 "price" integer, 5 "user_id" integer REFERENCES users(id) on update no action on delete no action, 6 "id" serial,"created_at" timestamp with time zone, 7 "updated_at" timestamp with time zone, 8 "deleted_at" timestamp with time zone , 9 PRIMARY KEY ("id") 10)

可见,从表的外键约束被定义了。也就是说 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 提供的接口了:

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

执行 SQL 语句:

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

关联关系

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

一对一、一对多关联

1type User struct { 2 3 4 gorm.Model 5 Code string `gorm:"primary_key"` 6 Name string 7 Products []Product 8} 9 10type Product struct { 11 12 13 gorm.Model 14 Code string `gorm:"primary_key"` 15 Price uint 16 UserID uint 17}

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

1type User struct { 2 3 4 gorm.Model 5 Code string `gorm:"primary_key"` 6 Name string 7 Products []Product `gorm:"foreignkey:UserID"` 8}

多对多关联

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

1type User struct { 2 3 4 gorm.Model 5 Code string `gorm:"primary_key"` 6 Name string 7 Products []Product `gorm:"many2many:user_language"` 8} 9 10type Product struct { 11 12 13 gorm.Model 14 Code string `gorm:"primary_key"` 15 Price uint 16}

会执行 SQL:

1CREATE TABLE "user_language" 2( 3 "user_id" integer, 4 "product_id" integer, 5 PRIMARY KEY ("user_id","product_id") 6)

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

示例

1// 文章表 2type Article struct { 3 4 5 ID int `json:"id"` 6 Title string `json:"title"` 7 CategoryId int `json:"category_id"` 8 Category Category `json:"category";gorm:"foreignkey:CategoryID"` // 一对多关系 9 Tag []Tag `gorm:"many2many:article_tag" json:"tag"` // 多对多关系 10} 11 12// 文章_标签多对多中间表 13// 默认的,article_id 字段对应 article 表 id,tag_id 字段对应 tag 表 id 14type ArticleTag struct { 15 16 17 ID int `json:"id"` 18 ArticleId string `json:"article_id"` 19 TagId string `json:"tag_id"` 20} 21 22// 标签表 23type Tag struct { 24 25 26 ID int `json:"id" ` 27 TagName string `json:"tag_name"` 28} 29 30// 分类表 31type Category struct { 32 33 34 ID int `json:"id"` 35 CategoryName string `json:"category_name"` 36 Status int `json:"status"` 37}
  • 查一列:

    func (a *Article) ListArticle(title string) (Article, error) {

    1query := database.GormPool 2 3var article Article 4query.Where("title like ?", "%"+title+"%").First(&article) 5fmt.Println(article) 6 7err := query.Model(&article). 8 Related(&article.Category). 9 Related(&article.Tag, "tag"). 10 Find(&article).Error 11 12if err != nil && err != gorm.ErrRecordNotFound { 13 14 15 return article, nil 16} 17 18return 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) {

    1query := database.GormPool 2 3err = query.Model(articles). 4 Where("title like ?", "%"+title+"%"). 5 Preload("Category"). 6 Preload("Tag").Find(&articles).Error 7 8if err != nil && err != gorm.ErrRecordNotFound { 9 10 11 return 12} 13return

    }

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

点赞
收藏

评论区

加载中...

相关推荐

sqlserver2005创建唯一约束的方法

对于一个表中非主键列的指定列,唯一(UNIQUE约束|:强制非主键上的实体完整性的约束。UNIQUE约束确保未输入重复值,并创建一个索引以增强性能。)约束确保不会输入重复的值。例如,在employee表中emp\_id列是主键,可以定义一个唯一约束来要求表中社会安全号码(ssn)列的项是唯一的。在数据库关系图中,可以使用"索引/键"属性页创建、

MySQL字段约束及多表查询

前言:mysql的字段约束是以后必不可免的,下面主要写了四个:主键约束用于唯一且不能为空;非空约束即不能为空可以重复;唯一约束即可以为空但必须唯一;外键约束是让表与表之间有一定的关联;当然如何使用还看下文,多表就不在这总结了。如果你对前面的知识有所遗忘或感兴趣MySQL数据库表的模糊/多行/分组/排序/分页查询以及字mysql数据类型的讲解

MySQL创建表时加入的约束以及外键约束的的意义

1,创建表时加入的约束a) 非空约束,notnullb) 唯一约束,uniquec) 主键约束,primarykeyd) 外键约束,foreignkey1,非空约束,针对某个字段设置其值不为空,如:学生的姓名不能为空droptableifexistst_studen

MySQL字段完整性约束(重要)

\TOC\完整性约束(重要)primarykey:主键,唯一标识,表都会拥有,不设置为默认找第一个不空,唯一字段,未标识则创建隐藏字段foreignkey:外键,外键要通过foreignkey语法建立表与表之间的关联uniquekey:唯一性数据,该条字段的值需要保证唯一

MySQL创建索引

创建索引方法一:创建表时  CREATETABLE表名(字段名1数据类型完整性约束条件…,字段名2数据类型完整性约束条件…,UNIQUE|FULLTEXT|

MySQL中添加、删除约束

MySQL中6种常见的约束:主键约束(primarykey)、外键约束(foreignkey)、非空约束(notnull)、唯一性约束(unique)、默认值约束(defualt)、自增约束(aoto\_increment),下面是添加、删除这几种约束的一些方法。\我已经建了数据库;1\添加约束21、建表时添加约