gorm中的数据库完整性约束(1)


写这篇文章的初衷是由于自己一直对数据库的一些基本知识了解得不是很透彻,加上gorm文档中对数据库完整性描述简直让人摸不着头脑。趁着这个机会,我们来整合一下这些知识,为后面更深入地使用gorm打下基础。其次,可能许多同学在阅读gorm的文档时,也有同样的疑惑,希望大家一起讨论,共同进步。

温故而知新一

超键:是一个或者多个属性的集合,这些属性的组合可以使我们在一个关系中唯一地标识一个元组。
候选键: 去掉冗余属性之后的最小超键。
主键:用来标示某个元组在它所存在的关系中是是唯一的。通俗来说,主键是介于超键和候选键之间的key。

主键约束(非空且唯一)

首先我们来看看数据库完整性规范中的第一条,实体完整性约束:每个表有且仅有一个主键,每一个主键值必须唯一,而且不允许为“空”(NULL)或重复。我们首先对Product结构体进行自动迁移,Debug方法可以帮助我们打印sql语句,调试起来很方便。

var (
	db  *gorm.DB
	err error
)

type Product struct {
	gorm.Model  // grom.Model是gorm预定义的结构,用于实现软删除 
	Code  string `gorm:"primary_key"`
	Price uint	
}

//type Model struct {
//    ID uint `gorm:"primary_key"`
//    CreatedAt time.Time
//    UpdatedAt time.Time
//    DeletedAt *time.Time `sql:"index"`
//}

func main() {
	db, err := gorm.Open("postgres", "host=localhost user=testuser dbname=testdb sslmode=disable password=123456")
	defer db.Close()
	fmt.Println(err)
	if err == nil {
		db.Debug().AutoMigrate(&Product{})
	}
	
//CREATE TABLE "products" ("id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone,"code" text,"price" integer , PRIMARY KEY ("id","code"))  
	
//CREATE INDEX idx_products_deleted_at ON "products"(deleted_at)  

从 sql PRIMARY KEY (“id”,“code”)) 中,我们可以知道,在这次数据库迁移中,我们定义了联合主键。因此,我们可以下定论,Gorm实现了对数据库实体完整性支持,即可以支持字段主键,也可以支持联合主键。在这里,有同学可能觉得这是很稀松平常的事情,但是当你往下看,或许又是另一翻感悟。

在这里我们可以顺带提一下ORM中的命名规范,为工程项目建立规范标准,也是一件很重要的事情:

单数变复数驼峰式的命名方法
规范模型名统一为单数,对应的数据库表名为复数若结构体名由多个单词组成,对应的数据表将使用下划线
示例Book(模型名称) —> books(数据表名)BookClub(模型类名) —> book_clubs(数据表名)

温故而知新二

外键: 一个关系模式(r1)可能在它的属性中包含另一个关系模式(r2)的主键,这个属性在r1上被称为外键,关系r1被称为外键依赖的参照关系,r2叫做外键依赖的被参照关系

关联外键: 这个术语的英文叫AssociationForeignKey,可以用于指定被参照关系中(r2)中特定字段。

外键约束

Belongs To

首先我们来看看gorm文档中belongs to关系。belongs_to 关联创建两个模型之间一对一的关系,product belongs to user,声明所在的模型实例属于另一个模型的实例。 在我们下面声明的例子中,有商品和用户两个模型,而每个商品只能指定一个用户。

type Product struct {
    Code string  `gorm:"primary_key"`
    Price uint
    UserID uint 
    User User   // 用于声明 Product belongs to User,
    gorm.Model
}

type User struct {
    gorm.Model
    Code string  `gorm:"primary_key"`
    Name string
}

func main() {
	db, err := gorm.Open("postgres", "host=localhost user=testuser dbname=testdb sslmode=disable password=123456")
	defer db.Close()
	fmt.Println(err)
	if err == nil {
		db.Debug().AutoMigrate(&User)AutoMigrate(&Product{})
	}
}	
//CREATE TABLE "products" ("id" serial,"created_at" timestamp with time zone,"updated_at" timestamp with time zone,"deleted_at" timestamp with time zone,"code" text,"price" integer , PRIMARY KEY ("id","code")) 

//CREATE INDEX idx_products_deleted_at ON "products"(deleted_at) 

我们可以在sql中发现,Product结构体中的成员User并无实际用处,其作用只是用于表示 product belongs to user的关联关系。其次,此次迁移并没有添加任何的外键约束。

然后在main方法中加入这个语句,

user := User{Code: "test", Name: "test"}
db.Debug().Create(&user)
// INSERT  INTO "users" ("created_at","updated_at","deleted_at","code","name") VALUES ('2019-04-25 23:40:45','2019-04-25 23:40:45',NULL,'test','test') 
db.Debug().Model(&user).Related(&product)
//  SELECT * FROM "products"  WHERE "products"."deleted_at" IS NULL AND (("user_id" = 5))  

Has one

has_one 关联也建立两个模型之间的一对一关系,但语义和结果有点不一样。这种关联表示模型的实例包含或拥有另一个模型的实例。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值