gorm 基本操作

编辑于 2022-09-04 22:39:25 阅读 999
type Test struct {
	Id         int    `json:"id"`
	Name       string `json:"name"`
	Memo       string `json:"memo"`
	CreateTime string `json:"create_time"`
	UpdateTime string `json:"update_time"`
	DeleteTime string `json:"delete_time"`
}

// 设置表名
func (Test) TableName() string {
	return "cw_test"
}

查询

检索单个对象

  • First:获取第一条记录(主键升序)
  • Take:获取一条记录,没有指定排序字段
  • Last:获取最后一条记录(主键降序)

下面以 First 为例,第一种:

	test := &Test{}
	result := orm.Db.First(&test)
	fmt.Println(result.RowsAffected) //返回找到的记录数: 0 or 1
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		fmt.Println("not found")
		return
	}
	data, _ := json.Marshal(&test)
	fmt.Printf("%s\n", data)

第二种:

	result := map[string]interface{}{}
	orm.Db.Model(&Test{}).First(&result)
	data, _ := json.Marshal(&result)
	fmt.Printf("%s\n", data)

输出

{"create_time":"0","delete_time":"0","id":1,"memo":"b","name":"a","update_time":"0"}

用主键检索

	//test := &Test{}

	//result := orm.Db.First(&test, 2)
	//result := orm.Db.First(&test, "name = ?", "aa")

	test := &Test{Id: 2}
	result := orm.Db.First(&test)

	fmt.Println(result.RowsAffected) //返回找到的记录数: 0 or 1
	if errors.Is(result.Error, gorm.ErrRecordNotFound) {
		fmt.Println("not found")
		return
	}

	data, _ := json.Marshal(&test)
	fmt.Printf("%s\n", data)

	//db.Model()
	var result Test
	orm.Db.Model(Test{Id: 2}).First(&result)
	data, _ := json.Marshal(&result)
	fmt.Printf("%s\n", data)

输出

{"id":2,"name":"aa","memo":"bb","create_time":"0","update_time":"0","delete_time":"0"}

find(in)

	var tests []*Test
	orm.Db.Find(&tests, []int{1, 2, 3})
	data, _ := json.Marshal(&tests)
	fmt.Printf("%s\n", data)

输出

[{"id":1,"name":"a","memo":"b","create_time":"0","update_time":"0","delete_time":"0"},{"id":2,"name":"aa","memo":"bb","create_time":"0","update_time":"0","delete_time":"0"}]

检索全部对象

无条件查全部

	var tests []*Test
	result := orm.Db.Find(&tests)
	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("not found")
		return
	}

	data, _ := json.Marshal(&tests)
	fmt.Printf("%s\n", data)

输出

[{"id":1,"name":"a","memo":"b","create_time":"0","update_time":"0","delete_time":"0"},{"id":2,"name":"aa","memo":"bb","create_time":"0","update_time":"0","delete_time":"0"}]

条件

String 条件

	var tests []*Test

	result := orm.Db.Where("name <> ?", "jinzhu").Find(&tests)
	//result := orm.Db.Where("name IN ?", []string{"jinzhu", "jinzhu 2"}).Find(&tests)
	//result := orm.Db.Where("name LIKE ?", "%jin%").Find(&tests)
	//result := orm.Db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&tests)
	//result := orm.Db.Where("updated_at > ?", lastWeek).Find(&tests)
	//result := orm.Db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&tests)

	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("not found")
		return
	}

	data, _ := json.Marshal(&tests)
	fmt.Printf("%s\n", data)

Struct & Map 条件

// Struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 ORDER BY id LIMIT 1;

// Map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;

// Slice of primary keys
db.Where([]int64{20, 21, 22}).Find(&users)
// SELECT * FROM users WHERE id IN (20, 21, 22);

注意:字段值为0,",false或其他零值,将不会用于构建查询条件。要在查询条件中包含0值,可以使用map,它将包含所有键值作为查询条件

db.Where(&User{Name: "jinzhu", Age: 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu";

db.Where(map[string]interface{}{"Name": "jinzhu", "Age": 0}).Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;

指定结构体查询字段

db.Where(&User{Name: "jinzhu"}, "name", "Age").Find(&users)
// SELECT * FROM users WHERE name = "jinzhu" AND age = 0;

db.Where(&User{Name: "jinzhu"}, "Age").Find(&users)
// SELECT * FROM users WHERE age = 0;

创建

创建记录

	test := Test{Name: "zhangshan3", Memo: "真棒3", CreateTime: helper.GetUnix()}

	result := orm.Db.Create(&test)
	//result := orm.Db.Select("Name", "CreateTime").Create(&test) //除了Name,CreateTime,其他字段为空
	//result := orm.Db.Omit("Memo").Create(&test) //填充所有字段,除了Memo

	fmt.Println(test.Id)             //返回插入数据的主键
	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("insert error")
		return
	}

	data, _ := json.Marshal(&test)
	fmt.Printf("%s\n", data)

批量插入

	tests := []Test{{Name: "jinzhu1"}, {Name: "jinzhu2", CreateTime: helper.GetUnix()}, {Name: "heihei"}}
	result := orm.Db.Create(&tests)
	//result := orm.Db.CreateInBatches(tests, 2) //分批创建,一批2个

	for _, user := range tests {
		fmt.Println(user.Id) // 1,2,3
	}
	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil { //某条数据出错,将导致全部错误,但mysql的主键会被占用
		fmt.Println("insert error")
		return
	}

	data, _ := json.Marshal(&tests)
	fmt.Printf("%s\n", data)

创建钩子

GORM 允许用户定义的钩子有 BeforeSave, BeforeCreate, AfterSave, AfterCreate 创建记录时将调用这些钩子方法

func (u *User) BeforeCreate(tx *gorm.DB) (err error) {
  u.UUID = uuid.New()

    if u.Role == "admin" {
        return errors.New("invalid role")
    }
    return
}

如果您想跳过 钩子 方法,您可以使用 SkipHooks 会话模式,例如:

DB.Session(&gorm.Session{SkipHooks: true}).Create(&user)

DB.Session(&gorm.Session{SkipHooks: true}).Create(&users)

DB.Session(&gorm.Session{SkipHooks: true}).CreateInBatches(users, 100)

根据 Map 创建

	result := orm.Db.Model(&Test{}).Create(map[string]interface{}{
		"Name": "jinzhu", "Memo": "真棒3",
	})
	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("insert error")
		return
	}

// batch insert from `[]map[string]interface{}{}`
db.Model(&User{}).Create([]map[string]interface{}{
  {"Name": "jinzhu_1", "Age": 18},
  {"Name": "jinzhu_2", "Age": 20},
})

更新

Save 是保存所有字段,你需要先查出来(test),在test的基础上修改

	test := Test{Id: 21}

	orm.Db.First(&test)

	test.Name = "jinzhu up.."
	test.Memo = "up.."
	test.UpdateTime = helper.GetUnix()
	result := orm.Db.Save(&test)
	//result := orm.Db.Table("cw_test").Where("id = ?", 21).Update("name", "hello")

	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("update error")
		return
	}

	data, _ := json.Marshal(&test)
	fmt.Printf("%s\n", data)

更新单个列,Update 为部分更新

	test := Test{Id: 21}
	result := orm.Db.Model(&test).Update("name", "hello222")

	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("update error")
		return
	}

	data, _ := json.Marshal(&test)
	fmt.Printf("%s\n", data)

// 条件更新
db.Model(&User{}).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE active=true;

// 根据条件和 model 的值进行更新
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;

更新多列

Updates 方法支持 struct 和 map[string]interface{} 参数。当使用 struct 更新时,默认情况下,GORM 只会更新非零值的字段

	test := Test{Id: 21}
	result := orm.Db.Model(&test).Updates(Test{Name: "hello33", Memo: "hhh", UpdateTime: helper.GetUnix()})
	//result := orm.Db.Model(&test).Updates(map[string]interface{}{"name": "hello", "Memo": 18})

	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("update error")
		return
	}

	data, _ := json.Marshal(&test)
	fmt.Printf("%s\n", data)

注意 当通过 struct 更新时,GORM 只会更新非零字段。

更新选定字段

如果您想要在更新时选定、忽略某些字段,您可以使用 Select、Omit

	test := Test{Id: 21}
	result := orm.Db.Model(&test).Select("Name", "Memo").Updates(Test{Name: "new_name", Memo: "0"})

	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("update error")
		return
	}

	data, _ := json.Marshal(&test)
	fmt.Printf("%s\n", data)

// 使用 Map 进行 Select
// User's ID is `111`:
db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET name='hello' WHERE id=111;

db.Model(&user).Omit("name").Updates(map[string]interface{}{"name": "hello", "age": 18, "active": false})
// UPDATE users SET age=18, active=false, updated_at='2013-11-17 21:34:10' WHERE id=111;

// 使用 Struct 进行 Select(会 select 零值的字段)
db.Model(&user).Select("Name", "Age").Updates(User{Name: "new_name", Age: 0})
// UPDATE users SET name='new_name', age=0 WHERE id=111;

// Select 所有字段(查询包括零值字段的所有字段)
db.Model(&user).Select("*").Update(User{Name: "jinzhu", Role: "admin", Age: 0})

// Select 除 Role 外的所有字段(包括零值字段的所有字段)
db.Model(&user).Select("*").Omit("Role").Update(User{Name: "jinzhu", Role: "admin", Age: 0})

更新 Hook

对于更新操作,GORM 支持 BeforeSave、BeforeUpdate、AfterSave、AfterUpdate 钩子,这些方法将在更新记录时被调用

func (u *User) BeforeUpdate(tx *gorm.DB) (err error) {
    if u.Role == "admin" {
        return errors.New("admin user not allowed to update")
    }
    return
}

批量更新

无主键更新

	result := orm.Db.Model(Test{}).Where("name = ?", "new_name").Updates(Test{Name: "new_name", Memo: "10"})

	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("update error")
		return
	}

// 根据 struct 更新
db.Model(User{}).Where("role = ?", "admin").Updates(User{Name: "hello", Age: 18})
// UPDATE users SET name='hello', age=18 WHERE role = 'admin';

// 根据 map 更新
db.Table("users").Where("id IN ?", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);

删除

删除一条记录

	test := Test{Id: 21}
	result := orm.Db.Delete(&test)

	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("del error")
		return
	}

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

根据主键删除

	result := orm.Db.Delete(&Test{}, 20)

	fmt.Println(result.RowsAffected) //返回找到的记录总数
	if result.Error != nil {
		fmt.Println("del error")
		return
	}

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);

批量删除

无主键删除

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

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

逻辑删

删除方法不变,区别在结构体定义

type Test struct {
	Id         int            `json:"id"`
	//DeleteTime gorm.DeletedAt `json:"delete_time"` //逻辑删除时将该字段更新为Y-m-d H:i:s
	DeleteTime soft_delete.DeletedAt `json:"delete_time"`// 逻辑删除时将该字段更新为时间戳
}

注意,使用 soft_delete.DeletedAt 类型时需要导入 gorm.io/plugin/soft_delete

广而告之,我的新作品《语音助手》上架Google Play了,欢迎下载体验