删除一条记录

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

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

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

根据主键删除

GORM 允许通过主键(可以是复合主键)和内联条件来删除对象,它可以使用数字(如以下例子。也可以使用字符串——译者注)。查看 查询-内联条件(Query Inline Conditions) 了解详情。

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

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

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

Delete Hook

对于删除操作,GORM 支持 BeforeDelete、AfterDelete Hook,在删除记录时会调用这些方法,查看 Hook 获取详情

1. func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
2. if u.Role == "admin" {
3. return errors.New("admin user not allowed to delete")
4. }
5. return
6. }

批量删除

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

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

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

阻止全局删除

如果在没有任何条件的情况下执行批量删除,GORM 不会执行该操作,并返回 ErrMissingWhereClause 错误

对此,你必须加一些条件,或者使用原生 SQL,或者启用 AllowGlobalUpdate 模式,例如:

1. db.Delete(&User{}).Error // gorm.ErrMissingWhereClause

3. db.Where("1 = 1").Delete(&User{})
4. // DELETE FROM `users` WHERE 1=1

6. db.Exec("DELETE FROM users")
7. // DELETE FROM users

9. db.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})
10. // DELETE FROM users

返回删除行的数据

返回被删除的数据,仅适用于支持 Returning 的数据库,例如:

1. // 返回所有列
2. var users []User
3. DB.Clauses(clause.Returning{}).Where("role = ?", "admin").Delete(&users)
4. // DELETE FROM `users` WHERE role = "admin" RETURNING *
5. // users => []User{{ID: 1, Name: "jinzhu", Role: "admin", Salary: 100}, {ID: 2, Name: "jinzhu.2", Role: "admin", Salary: 1000}}

7. // 返回指定的列
8. DB.Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Delete(&users)
9. // DELETE FROM `users` WHERE role = "admin" RETURNING `name`, `salary`
10. // users => []User{{ID: 0, Name: "jinzhu", Role: "", Salary: 100}, {ID: 0, Name: "jinzhu.2", Role: "", Salary: 1000}}

软删除

如果您的模型包含了一个 gorm.deletedat 字段(gorm.Model 已经包含了该字段),它将自动获得软删除的能力!

拥有软删除能力的模型调用 Delete 时,记录不会从数据库中被真正删除。但 GORM 会将 DeletedAt 置为当前时间, 并且你不能再通过普通的查询方法找到该记录。

1. // user 的 ID 是 `111`
2. db.Delete(&user)
3. // UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;

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

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

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

1. type User struct {
2. ID      int
3. Deleted gorm.DeletedAt
4. Name    string
5. }

查找被软删除的记录

您可以使用 Unscoped 找到被软删除的记录

1. db.Unscoped().Where("age = 20").Find(&users)
2. // SELECT * FROM users WHERE age = 20;

永久删除

您也可以使用 Unscoped 永久删除匹配的记录

1. db.Unscoped().Delete(&order)
2. // DELETE FROM orders WHERE id=10;

Delete Flag

将 unix 时间戳作为 delete flag

1. import "gorm.io/plugin/soft_delete"

3. type User struct {
4. ID        uint
5. Name      string
6. DeletedAt soft_delete.DeletedAt
7. }

9. // 查询
10. SELECT * FROM users WHERE deleted_at = 0;

12. // 删除
13. UPDATE users SET deleted_at = /* current unix second */ WHERE ID = 1;

INFO 在配合 unique 字段使用软删除时,您需要使用这个基于 unix 时间戳的 DeletedAt 字段创建一个复合索引,例如:

1. import “gorm.io/plugin/soft_delete”

type User struct { ID uint Name string gorm:"uniqueIndex:udx_name" DeletedAt soft_delete.DeletedAt gorm:"uniqueIndex:udx_name" }

使用 1 / 0 作为 delete flag

1. import "gorm.io/plugin/soft_delete"

3. type User struct {
4. ID    uint
5. Name  string
6. IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
7. }

9. // 查询
10. SELECT * FROM users WHERE is_del = 0;

12. // 删除
13. UPDATE users SET is_del = 1 WHERE ID = 1;