首页>>后端>>Golang->Golang GORM实战(三)

Golang GORM实战(三)

时间:2023-12-01 本站 点击:0

文章首发于公众号【程序员读书】,欢迎关注。

这是《Golang GORM实战》系列的第三篇,在这篇文章中我们来聊一聊GORM数据模型的一些细节。

模型定义

GORM的数据模型是一个标准的Go struct,一个数据模型代表一张数据表,模型由基本数据类型和实现了Scanner和Valuer接口的自定义类型及其指针或者别名组成,如:

typeUserstruct{IDuintNamestringEmail*stringAgeuint8Birthday*time.TimeMemberNumbersql.NullStringActivatedAtsql.NullTimeCreatedAttime.TimeUpdatedAttime.Time}

gorm.Model

对于一张数据表的每一条数据来说,都有自增主键,创建、更新与删除时间等比较通用的字段,因此GORM将其抽出来并定义了gorm.Model,如:

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}

如果有需要,我们可以将gorm.Model嵌入到我们的模型中,而不用重复定义那几个字段,如:

typeUserstruct{gorm.ModelNamestring}

上面嵌入gorm.Model的User等同于下面的User:

typeUserstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`Namestring}

嵌入结构体

上面我们已经在自己定义的结构体中嵌入gorm.Model,当然,我们也可以嵌入自定义的结构,匿名嵌入,这种方式与上面嵌入gorm.Model相同,如:

typeUserstruct{UsernamestringAgeint}typeHousestruct{IDintNamestringUser}//等同于typeHousestruct{IDintNamestringUsernamestringAgeint}

而非匿名嵌入,也就是正常的结构体字段,则需要声明字段标签embedded才可以嵌入,否则会被GORM当作关联模型处理,但于未定义关联关系,所以会报错,如:

//错误typeHousestruct{IDintNamestringUserUser}//正确typeHousestruct{IDintNamestringUserUser`gorm:"embedded"`}

另外,无论是正常结构体嵌入还是匿名嵌入,都可以使用字段标签embeddedPrefix来指定嵌入结构全部字段的前缀,如:

typeHousestruct{IDintNamestringUserUser`gorm:"embedded;embeddedPrefix:house_"`}//等同于typeHousestruct{IDintNamestringHouseUsernamestringHouserAgeint}

主键ID

GORM默认会把ID作为数据表的主键,如:

typeUserstruct{IDstring//默认情况下,名为`ID`的字段会作为表的主键Namestring}

如果ID是整型且为自增字段的话,则在新增时,会自动填充该值,如:

//ID此时为0varu=&User{Name:"小张"}//创建成功后,此时ID自动填充为数据表自增字段的值db.Create(u)

如果想设置其他字段为主键的话,可以通过字段标签primaryKey来指定,如:

typeUserstruct{UserIDstring`gorm:"primaryKey"`Namestring}

另外,也可以将多个字段设置为字段,而多个字段组成的主键也叫复合主键,如:

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}0

无论是ID,还是通过primaryKey设置的单字段主键或联合主键,如果字段的数据类型为整型,GORM都会把该字段设置为自增字段(AUTO_INCREMENT),可以通过autoIncrement设置为false来禁用这个功能,如:

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}1

时间追踪

GORM约定使用CreatedAt,Updatedat,DeletedAt追踪记录创建,更新,软删除的时间,如果在数据模型中定义了这几个字段,则在创建、更新、软删除记录时,会自动填充时间。

CreatedAt

如果数据模型有CreatedAt字段时,在创建记录时,如果没有指CreatedAt的值,则会将字段的值设置为当前时间。

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}2

也可以自己指定

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}3

也可以手动修改

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}4

UpdatedAt

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}5

DeletedAt

DeletedAt字段在使用Delete方法删除数据表记录会起作用,具体我们在系列的其他文章讲解到删除记录会涉及到。

覆盖表名

GORM使用结构体的蛇形命名作为数据表名称,如,对于User结构体来说,其表名为users,而GameUser结构的表名为game_users。

不过,如果不想按GORM的规则来指定数据表名,我们可以让数据模型实现Tabler接口,该接口的定义如下:

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}6

让User结构体实现Tabler接口,如:

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}7

当然,除了定义模型的TableName方法外,也可以使用Scope动态生成表名,或者在执行GORM的Create, First, Find, Take, Save, Update, Delete等方法时,临时指定数据表名,当然如果你想指定模型的表名的话,定义模型的TableName方法是最简单,因此推荐通过这种方法来指定表名。

覆盖列名

数据表的列名使用的也是数据模型的蛇形命名,如:

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}8

不过,可以使用column标签来覆盖列表,如:

//gorm.Model的定义typeModelstruct{IDuint`gorm:"primaryKey"`CreatedAttime.TimeUpdatedAttime.TimeDeletedAtgorm.DeletedAt`gorm:"index"`}9

标签(tag)

字段标签

对于数据模型(model)来说,字段标签并不是必须的,而是可选的,tag大小写不敏感,如primarykeyprimaryKey是一样的,不过还是推荐按下表列出的名称去使用。

标签名(tag)标签说明column指定数据表列名type列数据类型size指定列的大小primaryKey指定列为主键,默认ID为主键unique指定列为唯一default指定默认值precision指定列的精度scale指定列大小not null指定列为 NOT NULLautoIncrement指定列为自动增长autoIncrementIncrement自动步长,控制连续记录之间的间隔embedded嵌套字段embeddedPrefix嵌入字段的列名前缀autoCreateTime创建时追踪当前时间,对于 int 字段,它会追踪秒级时间戳,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoCreateTime:nanoautoUpdateTime创建/更新时追踪当前时间,对于 int 字段,它会追踪秒级时间戳,您可以使用 nano/milli 来追踪纳秒、毫秒时间戳,例如:autoUpdateTime:milliindex根据参数创建索引,多个字段使用相同的名称则创建复合索引,查看 索引 获取详情uniqueIndex与 index 相同,但创建的是唯一索引check创建检查约束,例如 check:age > 13,查看 约束 获取详情<-设置字段写入的权限, <-:create 只创建、<-:update 只更新、<-:false 无写入权限、<- 创建和更新权限->设置字段读的权限,->:false 无读权限-忽略此字段comment创建表时字段的注释

上述的字段标签有很大一部部分是用于迁移数据表的,不过这里不推荐使用GORM的数据迁移功能,这是因为对数据表的创建、删除、修改都是比较重大的变更和高危操作,因此需要严格评估后再实施操作,而不应该写在程序代码里。

而对于上述的标签的说明,有个大概印象就好,如须使用,再查看文档即可。

关联标签

另外,下面列出来的字段标签与数据模型的关联有关,我们在之后的文章再行讲解。

标签名(tag)标签说明foreignKey指定当前模型的列作为连接表的外键references指定引用表的列名,其将被映射为连接表外键polymorphic指定多态类型,比如模型名polymorphicValue指定多态值、默认表名many2many指定连接表表名joinForeignKey指定连接表的外键列名,其将被映射到当前表joinReferences指定连接表的外键列名,其将被映射到引用表constraint关系约束,例如:OnUpdate、OnDelete

小结

对于GORM来说,数据模型其实是就是Go struct,对应一个数据库的数据表,GORM约定了许多数据模型到数据表的映射规则,比如表名与列名的蛇形复数命命规则,默认ID字段为主键等,但我们仍然可以通过对数据模型方法和标签的定义来改变这些约定,比如通过TableName方法来改变模型对应的数据表等,对GORM数据模型的理解,可以让我们更好地去使用GORM操作数据表。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Golang/5880.html