Gorm | 青训营笔记

119 阅读4分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 6 天

GORM 快速入门

安装

go get -u gorm.io/gorm
go get -u gorm.io/driver/sqlite

快速入门

这里使用mysql举例。首先我们需要新建一个数据库,例如db1

在Go语言中输入以下代码

package main

import (
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
)

type Userinfo struct {
	Id     uint
	Name   string
	Gender string
	Hobby  string
}

func main() {
	// 连接数据库
	dsn := "root:123456@tcp(127.0.0.1:3306)/db1?charset=utf8mb4&parseTime=True&loc=Local"
	db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})
	if err != nil {
		panic(err)
	}
	//自动迁移
	db.AutoMigrate(&Userinfo{})
	u1 := Userinfo{Id: 1, Name: "张三", Gender: "男", Hobby: "学习"}
	db.Create(&u1) //创建
}

以上代码执行结果如下

image.png

GORM 声明模型

模型定义

模型是标准的 struct,由 Go 的基本数据类型、实现了 Scanner 和 Valuer 接口的自定义类型及其指针或别名组成

例如:

type User struct {
	ID           uint
	Name         string
	Email        *string
	Age          uint8
	Birthday     *time.Time
	MemberNumber sql.NullString
	ActivatedAt  sql.NullTime
	CreatedAt    time.Time
	UpdatedAt    time.Time
}

约定

GORM 倾向于约定,而不是配置。默认情况下,GORM 使用 ID 作为主键,使用结构体名的蛇形复数作为表名,字段名的蛇形作为列名,并使用 CreatedAt、UpdatedAt 字段追踪创建、更新时间
遵循 GORM 已有的约定,可以减少您的配置和代码量。如果约定不符合您的需求,GORM 允许您自定义配置它们

gorm.Model

GORM 定义一个 gorm.Model 结构体,其包括字段 ID、CreatedAt、UpdatedAt、DeletedAt

// gorm.Model 的定义
type Model struct {
	ID        uint `gorm:"primaryKey"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt gorm.DeletedAt `gorm:"index"`
}

你可以将它嵌入到你的结构体中,以包含这几个字段

嵌入结构体

对于匿名字段,GORM 会将其字段包含在父结构体中,例如:

type User struct {
	gorm.Model
	Name string
}

// 等效于
type User struct {
	ID        uint `gorm:"primaryKey"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt gorm.DeletedAt `gorm:"index"`
	Name      string
}

对于正常的结构体字段,你也可以通过标签 embedded 将其嵌入,例如:

type Author struct {
	Name  string
	Email string
}

type Blog struct {
	ID      int
	Author  Author `gorm:"embedded"`
	Upvotes int32
}

// 等效于
type Blog struct {
	ID      int64
	Name    string
	Email   string
	Upvotes int32
}

并且,您可以使用标签 embeddedPrefix 来为 db 中的字段名添加前缀,例如:

type Blog struct {
	ID      int
	Author  Author `gorm:"embedded;embeddedPrefix:author_"`
	Upvotes int32
}

// 等效于
type Blog struct {
	ID          int64
	AuthorName  string
	AuthorEmail string
	Upvotes     int32
}

GORM 创建

创建记录

user := User{Name: "张三", Age: 18, Birthday: time.Now()}

result := db.Create(&user) // 通过数据的指针来创建

user.ID             // 返回插入数据的主键
result.Error        // 返回 error
result.RowsAffected // 返回插入记录的条数

用指定的字段创建记录

创建记录并更新给出的字段

db.Select("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`name`,`age`,`created_at`) VALUES ("jinzhu", 18, "2020-07-04 11:05:21.775")

创建一个记录且一同忽略传递给略去的字段值

db.Omit("Name", "Age", "CreatedAt").Create(&user)
// INSERT INTO `users` (`birthday`,`updated_at`) VALUES ("2020-01-01 00:00:00.000", "2020-07-04 11:05:21.775")

GORM 删除

删除一条记录

删除一条记录时,删除对象需要指定主键,否则会触发批量Delete,例如:

// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;

// 带额外条件的删除
db.Where("name = ?", "张三").Delete(&email)
// DELETE from emails where id = 10 AND name = "张三";

根据主键删除

GORM允许通过主键(可以是复合主键)和内联条件来删除对象,它可以使用数字,如以下例子

db.Delete(&User{}, 10)
// DELETE FROM users WHERE id = 10;

db.Delete(&User{}, "10")
// DELETE FROM users WHERE id = 10;

db.Delete(&users, []int{1,2,3})
// DELETE FROM users WHERE id IN (1,2,3);

批量删除

如果指定的值不包括主属性,那么 GORM 会执行批量删除,它将删除所有匹配的记录

db.Where("email LIKE ?", "%张三%").Delete(&Email{})
// DELETE from emails where email LIKE "%张三%";

db.Delete(&Email{}, "email LIKE ?", "%张三%")
// DELETE from emails where email LIKE "%张三%";

软删除

如果你的模型包含了一个gorm.deletedat字段(gorm.Model 已经包含了该字段),它将自动获得软删除的能力!拥有软删除能力的模型调用Delete时,记录不会被数据库删除。但GORM会将DeletedAt置为当前时间, 并且你不能再通过普通的查询方法找到该记录。

// user 的 ID 是 `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2022-03-04 10:16" WHERE id = 111;

// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2022-03-04 10:16" WHERE age = 20;

// 在查询时会忽略被软删除的记录
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;

如果你不想引入gorm.Model,你也可以这样启用软删除特性

type User struct {
	ID      int
	Deleted gorm.DeletedAt
	Name    string
}