Gorm 基础:表映射

这篇文章将以创建事件时间记录功能为示例,介绍如何使用 Gorm 完成数据库表的基本映射、简单的创建表数据操作和注意事项。

数据库表设计

设计一个事件时间记录功能通常需要记录事件的开始时间、结束时间和事件类型,以及一些额外的功能,像事件描述。下面提供一个简单的数据库表设计方案。

我们提供两张数据库表:记录类别表 Record_Type 和时间记录表 Time_Record。Record_Type 用于记录事件类型,时间记录表是主要的记录表,记录事件发生的起始时间和结束时间。基本结构如下:

Record_Type:

  • ID:唯一标识符
  • Type:时间类型

Time_Record:

  • ID:唯一标识符
  • start_time:事件起始时间
  • end_time:事件结束事件
  • Description:事件描述
  • type_id:事件类型ID

其中 Record_Type 和 Time_Record 的主键都是自增的唯一标识符,type_id 和 Record_Type 的 ID 建立外键约束,建表语句如下:

Record_Type:

CREATE TABLE Record_Types (
    ID INT AUTO_INCREMENT PRIMARY KEY,
    Type VARCHAR(255) NOT NULL
);

Time_Record:

CREATE TABLE Time_Records (
    ID INT AUTO_INCREMENT,
    start_time DATETIME NOT NULL,
    end_time DATETIME,
    Description TEXT,
    type_id INT,
    PRIMARY KEY (ID),
    FOREIGN KEY (type_id) REFERENCES Record_Types(ID)
);

需要注意的是这里的 start_time 非空而 end_time 可以为空,这会影响到我们 Go 语言中的结构体对应的字段类型。

使用 Gorm 映射数据库表

使用 Gorm 之后,我们可以使用 Go 语言中的结构体来映射数据库表,不同类型则对应不同字段。常见的映射有:INT 对应 intVARCHARTEXT 对应 stringDATETIME 等时间类型则使用 time.Time 来映射。上述映射都是针对数据库中的非空字段,而数据库中允许为空的字段,则替换成对应的指针类型。下面是实现上述示例映射的具体代码:

RecordType:

// RecordType 记录类别
type RecordType struct {
	// 主键
	ID   int `gorm:"primaryKey"`
	Type string
}

TimeRecord:

// TimeRecord 时间记录
type TimeRecord struct {
	// 主键
	ID          int `gorm:"primaryKey"`
	StartTime   time.Time
	EndTime     *time.Time
	Description string
	// 外键约束
	TypeId int `gorm:"check: ID <> 'RecordType''"`
}

可以注意到上述 EndTime 字段的数据类型为 *time.Time ,这正是因为 end_time 在数据库表中没有声明为非空,所以我们使用time.Time 的指针类型来表示。另外,在 Gorm 中主键和外键的声明则是通过标签来完成的。TimeRecord 表中 ID 字段类型声明后跟的 gorm:"primaryKey"就是主键标签。如果你需要建立联合主键,则可以通过对多个字段同时加上主键标签,并且注意字段顺序的编排,因为 Gorm 会根据字段顺序来确定联合主键的顺序。外键则是使用 gorm:"check: ID <> 'RecordType 标签来声明的其中的 RecordType 指定表,ID 指定表中的字段。

名称映射

我们在给结构体和字段体起名时需要额外注意 Gorm 的名称映射规则:

  1. 结构体的字段名称会默认映射为数据库表的字段名。但是结构体名需要是单数形式,例如 RecordType 对应表 record_typesTimeRecord 对应表 time_records

  2. RecordType 并不会映射为 recordtypes 而是带下划线的 record_types。这条规则同时适用于字段名和结构体名称。

通过 Gorm 插入表数据

结构体设计完成之后,我们可以创建一个专门用于插入数据行的函数,方便后续使用。而插入数据的方式也很简单,主要分两步:创建结构体,然后调用 *gorm.DB Create 即可。示例如下:

// CreateType 创建新记录类别
func CreateType(db *gorm.DB, typeName string) (*RecordType, *gorm.DB) {
	rtype := &RecordType{
		Type: typeName,
	}
	result := db.Create(rtype)
	return rtype, result
}
// StartRecord 开启新记录
func StartRecord(db *gorm.DB, description string, recordTypeId int) (*TimeRecord, *gorm.DB) {
	record := &TimeRecord{
		StartTime:   time.Now(),
		Description: description,
		TypeId:      recordTypeId,
	}
	result := db.Create(record)
	return record, result
}

可以注意到,对于自增的 ID 主键,我们在创建结构体时对其省略。但是需要注意的是对于非空且没有默认值的对象,我们进行省略是存在风险的,如 time.Time 类型的非空对象省略后,Gorm 会将结构体初始化时的零值赋给其转换的 SQL 语句从而导致错误。

到此,简单的 Gorm 表映射便完成了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值