Day04-GORM的CRUD接口 | 青训营笔记

190 阅读6分钟

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

GORM的CRUD接口

1、创建

1.1、创建记录

db.NewRecord (product): 用于检查主键是否为空.

user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
db.NewRecord(user) //返回 `true` ,因为主键为空
db.Create(&user)
db.NewRecord(user) // 在 `user` 创建之后返回 `false`

1.2、为结构体字段指定默认值

可以通过标签定义字段的默认值,例如:

type Person struct {
    ID int64
    Name string `gorm:"default:'galeone'"`
    Age int64
}
var person = Person{Age: 99, Name: ""}
db.Create(&person)
// INSERT INTO persons("age") values('99');
// SELECT name from persons WHERE ID=111; // 返回的主键是 111
// person.Name => 'galeone'

SQL 会排除那些没有值或者有零值的字段,在记录插入数据库之后,gorm将从数据库中加载这些字段的值。

2、查询

2.1、简单查询

获取第一条记录,按主键排序:

db.First(&user)
// SQLSELECT * FROM users ORDER BY id LIMIT 1;

获取一条记录,不指定排序:

db.Take(&user)
// SQLSELECT * FROM users LIMIT 1;

获取最后一条记录,按主键排序:

db.Last(&user)
// SQLSELECT * FROM users ORDER BY id DESC LIMIT 1;

获取所有的记录:

db.Find(&users)
// SQLSELECT * FROM users;

通过主键进行查询,适用于主键是数字类型:

db.First(&user, 10)
// SQLSELECT * FROM users WHERE id = 10;

2.2、条件查询——where

获取第一条匹配的记录:

db.Where("name = ?", "jinzhu").First(&user)
// SQLSELECT * FROM users WHERE name = 'jinzhu' limit 1;\

获取所有匹配的记录:

db.Where("name = ?", "jinzhu").Find(&users)
// SQLSELECT * FROM users WHERE name = 'jinzhu';

带其它关键字:

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

Struct & Map,通过struct进行查询的时候,GORM 将会查询这些字段的非零值, 意味着你的字段包 含 0 , '' , false 或者其他 零值, 将不会出现在查询语句中:

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

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

// 多主键 slice 查询
db.Where([]int64{20, 21, 22}).Find(&users)
// SQLSELECT * FROM users WHERE id IN (20, 21, 22);

2.3、Not

db.Not("name", "jinzhu").First(&user)
// SQLSELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;

// 不包含
db.Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&users)
// SQLSELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");

//不在主键 slice 中
db.Not([]int64{1,2,3}).First(&user)
// SQLSELECT * FROM users WHERE id NOT IN (1,2,3);

db.Not([]int64{}).First(&user)
// SQLSELECT * FROM users;

// 原生 SQL
db.Not("name = ?", "jinzhu").First(&user)
// SQLSELECT * FROM users WHERE NOT(name = "jinzhu");

// Struct
db.Not(User{Name: "jinzhu"}).First(&user)
// SQLSELECT * FROM users WHERE name <> "jinzhu";

2.4、Or

db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
// SQLSELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';

// Struct
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users)
// SQLSELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';

// Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find
(&users)
// SQLSELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';

3、高级查询

3.1、要从数据库检索指定的字段,默认情况下,将选择所有字段

db.Select("name, age").Find(&users)
// SQLSELECT name, age FROM users;

db.Select([]string{"name", "age"}).Find(&users)
// SQLSELECT name, age FROM users;

db.Table("users").Select("COALESCE(age,?)", 42).Rows()
// SQLSELECT COALESCE(age,'42') FROM users;

3.2、Order-By:排序

使用 Order 从数据库查询记录,当第二个参数设置为 true 时,将会覆盖之前的定义条件。

db.Order("age desc, name").Find(&users)
// SQLSELECT * FROM users ORDER BY age desc, name;

// 多个排序条件
db.Order("age desc").Order("name").Find(&users)
// SQLSELECT * FROM users ORDER BY age desc, name;

// 重新排序
db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
// SQLSELECT * FROM users ORDER BY age desc; (users1)
// SQLSELECT * FROM users ORDER BY age; (users2)

3.3、Limit——分页查询

指定要查询的最大记录数:

db.Limit(3).Find(&users)
// SQL:SELECT * FROM users LIMIT 3;

// 用 -1 取消 LIMIT 限制条件
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
// SQL:SELECT * FROM users LIMIT 10; (users1)
// SQL:SELECT * FROM users; (users2)

3.4、Scan

将查询结果放入另一个结构体中。

type Result struct {
Name string
Age int
}
var result Result
db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)

4、更新

4.1、更新所有字段

Save 方法:在执行 SQL 更新操作时将包含所有字段,即使这些字段没有被修改

db.First(&user)
user.Name = "jinzhu 2"
user.Age = 100

db.Save(&user)
// SQL:UPDATE users SET name='jinzhu 2', age=100, birthday='2023-1-17', updated_at = '2023-1-17 21:34:10' WHERE id=111;

4.2、更新选中的字段

如果在执行更新操作时只想更新或者忽略某些字段,可以使用 SelectOmit 方法。

db.Model(&user).Select("name").Updates(map[string]interface{}{"name": "hello","age": 18,"actived": false})
// SQLUPDATE users SET name='hello', updated_at='2023-1-17 21:34:10' WHERE id=111;

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

4.3、更新已更改的字段

如果你只想更新已经修改了的字段,可以使用 UpdateUpdates 方法。

// 如果单个属性被更改了,更新它
db.Model(&user).Update("name", "hello")
// SQLUPDATE users SET name='hello', updated_at='2023-1-17 21:34:10' WHERE id=111;

// 使用组合条件更新单个属性
db.Model(&user).Where("active = ?", true).Update("name", "hello")
// SQLUPDATE users SET name='hello', updated_at='2023-1-17 21:34:10' WHERE id=111 AND active=true;

// 使用 `map` 更新多个属性,只会更新那些被更改了的字段
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
// SQLUPDATE users SET name='hello', age=18, actived=false, updated_at='2023-1-17 21:34:10' WHERE id=111;

// 使用 `struct` 更新多个属性,只会更新那些被修改了的和非空的字段
db.Model(&user).Updates(User{Name: "hello", Age: 18})
// SQLUPDATE users SET name='hello', age=18, updated_at = '2023-1-17 21:34:10' WHERE id = 111;

//当使用结构体更新的时候, GORM 只会更新那些非空的字段
// 例如下面的更新,没有东西会被更新,因为像 "", 0, false 是这些字段类型的空值
db.Model(&user).Updates(User{Name: "", Age: 0, Actived: false})

5、删除

5.1、删除记录

注意:当删除一条记录的时候,你需要确定这条记录的主键有值,GORM会使用主键来删除这 条记录。如果主键字段为空,GORM会删除模型中所有的记录

// 删除一条存在的记录
db.Delete(&email)
// SQLDELETE from emails where id=10;

// 为删除 SQL 语句添加额外选项
db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
// SQLDELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);

5.2、批量删除:删除所有匹配的记录

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

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

5.3、软删除

如果模型中有 DeletedAt 字段,它将自动拥有软删除的能力!当执行删除操作时,数据并 不会永久的从数据库中删除,而是将 DeletedAt 的值更新为当前时间。

db.Delete(&user)
// SQLUPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;

// 批量删除
db.Where("age = ?", 20).Delete(&User{})
// SQLUPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;

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

// 使用 Unscoped 方法查找软删除记录
db.Unscoped().Where("age = 20").Find(&users)
// SQLSELECT * FROM users WHERE age = 20;

// 使用 Unscoped 方法永久删除记录
db.Unscoped().Delete(&order)
//SQLDELETE FROM orders WHERE id=10;