内容简介:在开发应用程序时,一般而言,我们是先设计好数据表,再使用开发语言建立对应的数据模型,不过,我们今天要讲的是一个逆向操作的过程,即如何通定义因此需要先讲讲怎么定义一般来说,我们说
在开发应用程序时,一般而言,我们是先设计好数据表,再使用开发语言建立对应的数据模型,不过,我们今天要讲的是一个逆向操作的过程,即如何通定义 GORM
框架的数据模型,然后再通过执行 GROM
框架编写的应用程序,用定义好数据模型在数据库中创建对应的数据表。
因此需要先讲讲怎么定义 GORM
的数据模型。
模型定义
一般来说,我们说 GROM
的模型定义,是指定义代表一个数据表的结构体( struct
),然后我们可以使用 GROM
框架可以将结构体映射为相对应的关系数据库的数据表,或者查询数据表中的数据来填充结构体,如下所示,我们定义了一个名为 Post
的结构体。
type Post struct { PostId int Uid int Title string Content string Type int CreatedAt time.Time UpdatedAt time.Time } 复制代码
创建好一个结构体只是第一步,不过先不着急要怎么去创建数据表,我们要先了解一下结构体与数据表之间的映射规则,主要有以下几点:
Struct tags
我们知道, Go
语言的结构体支持使用 tags
为结构体的每个字段扩展额外的信息,如使用标准库 encoding/json
包进行 JSON
编码时,便可以使用 tags
进行编码额外信息的扩展。
GROM
框架有自己的一个 tags
约定,如下所示:
Column 指定列名 Type 指定列数据类型 Size 指定列大小, 默认值255 PRIMARY_KEY 将列指定为主键 UNIQUE 将列指定为唯一 DEFAULT 指定列默认值 PRECISION 指定列精度 NOT NULL 将列指定为非 NULL AUTO_INCREMENT 指定列是否为自增类型 INDEX 创建具有或不带名称的索引, 如果多个索引同名则创建复合索引 UNIQUE_INDEX 和 INDEX 类似,只不过创建的是唯一索引 EMBEDDED 将结构设置为嵌入 EMBEDDED_PREFIX 设置嵌入结构的前缀 - 忽略此字段 复制代码
GROM还支持一些关联数据表的tags约定,有机会我讲讲GROM数据表关联的时候,会说到的。
上面列出的GORM支持的tags,方便我们定制结构体字段到数据表字段之间的映射规则,下面的代码,我们给 Post
结构体定制一些 tags
扩展,如下:
type Post struct { PostId int `gorm:"primary_key;auto_increment"` Uid int `gorm:"type:int;not null"` Title string `gorm:"type:varchar(255);not null"` Content string `gorm:"type:text;not null"` Type uint8 `gorm:"type:tinyint;default 1;not null"` CreatedAt time.Time UpdatedAt time.Time DeletedAt time.Time } 复制代码
从上面的例子我们可以看出 GORM
为数据模型的字段定义tags的格式,每个字段可以用多个类型的 tags
信息,不同的tag之间用分号分隔。
惯例
除了上面讲的 tags
定义了字段之间的映射规则外,Go将结构体映射为关系型数据表时,还有自己的一套惯例,或称为约定,主要有以下几点:
主键
GROM的约定中,一般将数据模型中的 ID
字段映射为数据表的主键,如下面定义的 TestModel
, ID
为主键, TestModel
的 ID
的数据类型为 string
,如果 ID
的数据类型为 int
,则GROM还会为该设置 AUTO_INCREMENT
,使用 ID
成为自增主键。
type TestModel struct{ ID int Name string } 复制代码
当然,我们也可以自定义主键字段的名称,如上面的 Post
结构体,我们设置了 PostId
字段为主键,如果我们定义了其他字段为主键,那么,就算结构体中仍有 ID
字段, GROM
框架也不会把 ID
字段当作主键了。
type Post struct { ID int PostId int `gorm:"primary_key;auto_increment"` Uid int `gorm:"type:int;not null"` Title string `gorm:"type:varchar(255);not null"` Content string `gorm:"type:text;not null"` Type uint8 `gorm:"type:tinyint;default 1;not null"` CreatedAt time.Time UpdatedAt time.Time DeletedAt time.Time } 复制代码
所以,我们在 Post
结构体中加一个 ID
字段, PostId
字段仍是主键,下面是在数据中使用 desc posts
语句打印出来的结果:
数据表映射规则
当我们使用结构体创建数据表时,数据表的名称默认为结构体的小写复数形式,如结构体 Post
对应的数据表名称为 posts
,当然我们也可以自己指定结构体对应的数据表名称,而不是用默认的。
为结构体加上 TableName()
方法,通过这个方法可以返回自定义的数据表名,如下:
//指定Post结构体对应的数据表为my_posts func (p Post) TableName() string{ return "my_posts" } 复制代码
数据表前缀
除了指定数据表名外,我们也可以重写 gorm.DefaultTableNameHandler
这个变量,这样可以为所有数据表指定统一的数据表前缀,如下:
gorm.DefaultTableNameHandler = func (db *gorm.DB, defaultTableName string) string { return "tb_" + defaultTableName; } 复制代码
这样的话,通过结构体 Post
创建的数据表名称则为 tb_posts
。
字段映射规则
结构体到数据表的名称映射规则为结构体名称的复数,而结构体的字段到数据表字段的默认映射规则是用下划线分隔每个大写字母开头的单词,如下:
type Prize struct { ID int PrizeName string } 复制代码
上面的结构体 Prize
中的 PrizeName
字段对应的数据表为 prize_name
,但我们把 PrizeName
改为 Prizename
时,则对应的数据表字段名称为 prizename
,这是为因为只分隔大写字段开头的单词。
当然,我们也可以为结构体的某个字段定义 tags
扩展信息,这样结构体字段到数据表字段的映规则就在 tags
中定义。
时间点追踪
前面我们说过,如果结构体中有名称为 ID
字段,则 GORM
框架会把该字段作为数据表的主键,除此之外,如果结构体中有 CreatedAt
, UpdatedAt
, DeletedAt
这几个字段的话,则 GROM
框架也会作一些特殊处理,规则如下:
CreatedAt:新增数据表记录的时候,会自动写入这个字段。 UpdatedAt:更新数据表记录的时候,会自动更新这个字段。 DeletedAt:当执行软删除的时候,会自动更新这个字段,表示删除时间 复制代码
gorm.Model
由于如果结构体中有 ID
, CreatedAt
, UpdatedAt
, DeletedAt
这几个比较通用的字段, GORM
框架会自动处理这几个字段,所以如果我们结构体需要这几个字段时,我们可以直接在自定义结构体中嵌入 gorm.Model
结构体, gorm.Model
的结构体如下:
type Model struct { ID uint `gorm:"primary_key"` CreatedAt time.Time UpdatedAt time.Time DeletedAt *time.Time `sql:"index"` } 复制代码
所以,如果我们在结构体 Prize
中嵌入 gorm.Model
,如下:
type Prize struct{ gorm.Model Name string } 复制代码
这样的话,则结构体 Prize
包含有五个字段了。
数据库迁移
我们这里所说的数据库迁移,即通过使用 GROM
提供的一系列方法,根据数据模型定义好的规则,进行创建、删除数据表等操作,也就是数据库的DDL操作。
GORM
提供对数据库进行DDL操作的方法,主要以下几类:
数据表操作
//根据模型自动创建数据表 func (s *DB) AutoMigrate(values ...interface{}) *DB //根据模型创建数据表 func (s *DB) CreateTable(models ...interface{}) *DB //删除数据表,相当于drop table语句 func (s *DB) DropTable(values ...interface{}) *DB //相当于drop table if exsist 语句 func (s *DB) DropTableIfExists(values ...interface{}) *DB //根据模型判断数据表是否存在 func (s *DB) HasTable(value interface{}) bool 复制代码
列操作
//删除数据表字段 func (s *DB) DropColumn(column string) *DB //修改数据表字段的数据类型 func (s *DB) ModifyColumn(column string, typ string) *DB 复制代码
索引操作
//添加外键 func (s *DB) AddForeignKey(field string, dest string, onDelete string, onUpdate string) *DB //给数据表字段添加索引 func (s *DB) AddIndex(indexName string, columns ...string) *DB //给数据表字段添加唯一索引 func (s *DB) AddUniqueIndex(indexName string, columns ...string) *DB 复制代码
数据迁移简单代码示例
注意,下面示例程序中 db
变量代表 gorm.DB
对象,其初始化过程可以参考我的上一篇文章。
type User struct { Id int //对应数据表的自增id Username string Password string Email string Phone string } func main(){ db.AutoMigrate(&Post{},&User{})//创建posts和users数据表 db.CreateTable(&Post{})//创建posts数据表 db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&Post{})//创建posts表时指存在引擎 db.DropTable(&Post{},"users")//删除posts和users表数据表 db.DropTableIfExists(&Post{},"users")//删除前会判断posts和users表是否存在 //先判断users表是否存在,再删除users表 if db.HasTable("users") { db.DropTable("users") } //删除数据表字段 db.Model(&Post{}).DropColumn("id") //修改字段数据类型 db.Model(&Post{}).ModifyColumn("id","varchar(255)") //建立posts与users表之间的外键关联 db.Model(&Post{}).AddForeignKey("uid", "users(id)", "RESTRICT", "RESTRICT") //给posts表的title字段添加索引 db.Model(&Post{}).AddIndex("index_title","title") //给users表的phone字段添加唯一索引 db.Model(&User{}).AddUniqueIndex("index_phone","phone") } 复制代码
小结
可能你会问,直接在数据库中进行数据表创建、删除等操作不就行了吗?为什么要在应用程序里去做这些操作呢?因为有些时候,我们不一定能登录到数据库系统当中,又或者,我们需要开发一个可以管理数据库的应用程序,这时候, GROM
框架提供的这些数据库迁移的能便派上用场了。
你的关注,是我写作路上最大的鼓励!
以上所述就是小编给大家介绍的《Golang数据库编程之GORM模型定义与数据库迁移》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:- 4 万字全面掌握数据库、数据仓库、数据集市、数据湖、数据中台
- Python3爬虫数据入数据库---把爬取到的数据存到数据库,带数据库去重功能
- Oracle数据库查询重复数据及删除重复数据方法
- sqlserver数据库获取数据库信息
- 从大数据到数据库
- node连接oracle数据库,更新数据后,数据库中不生效问题
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。