上回书说到,更新也叫修改,update,此章说明删除操作。
删除一条记录时,删除对象需要指定主键,否则会触发批量删除。
// Email 的 ID 是 `10`
db.Delete(&email)
// DELETE from emails where id = 10;
// 带额外条件的删除
db.Where("name = ?", "jinzhu").Delete(&email)
// DELETE from emails where id = 10 AND name = "jinzhu";
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 支持 BeforeDelete
、AfterDelete
Hook,在删除记录时会调用这些方法。
func (u *User) BeforeDelete(tx *gorm.DB) (err error) {
if u.Role == "admin" {
return errors.New("admin user not allowed to delete")
}
return
}
如果指定的值不包括主属性,那么 GORM 会执行批量删除,它将删除所有匹配的记录。
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%";
可以将一个主键切片传递给Delete 方法,以便更高效的删除数据量大的记录。
var users = []User{{ID: 1}, {ID: 2}, {ID: 3}}
db.Delete(&users)
// DELETE FROM users WHERE id IN (1,2,3);
db.Delete(&users, "name LIKE ?", "%jinzhu%")
// DELETE FROM users WHERE name LIKE "%jinzhu%" AND id IN (1,2,3);
当执行不带任何条件的批量删除时,GORM将不会运行并返回ErrMissingWhereClause 错误。
db.Delete(&User{}).Error // gorm.ErrMissingWhereClause
db.Delete(&[]User{{Name: "jinzhu1"}, {Name: "jinzhu2"}}).Error // gorm.ErrMissingWhereClause
如果一定要这么做,你必须添加一些条件,或者使用原生SQL,或者开启AllowGlobalUpdate 模式。
db.Where("1 = 1").Delete(&User{})
// DELETE FROM `users` WHERE 1=1
db.Exec("DELETE FROM users")
// DELETE FROM users
db.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})
// DELETE FROM users
返回被删除的数据,仅当数据库支持回写功能时才能正常运行。
// 回写所有的列
var users []User
DB.Clauses(clause.Returning{}).Where("role = ?", "admin").Delete(&users)
// DELETE FROM `users` WHERE role = "admin" RETURNING *
// users => []User{{ID: 1, Name: "jinzhu", Role: "admin", Salary: 100}, {ID: 2, Name: "jinzhu.2", Role: "admin", Salary: 1000}}
// 回写指定的列
DB.Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Delete(&users)
// DELETE FROM `users` WHERE role = "admin" RETURNING `name`, `salary`
// users => []User{{ID: 0, Name: "jinzhu", Role: "", Salary: 100}, {ID: 0, Name: "jinzhu.2", Role: "", Salary: 1000}}
模型包含了 gorm.DeletedAt字段(该字段也被包含在gorm.Model中),那么该模型将会自动获得软删除的能力!(经常用
)
当调用Delete时,GORM并不会从数据库中删除该记录,而是将该记录的DeleteAt设置为当前时间,而后的一般查询方法将无法查找到此条记录。
// user's ID is `111`
db.Delete(&user)
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
// Batch Delete
db.Where("age = ?", 20).Delete(&User{})
// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
// Soft deleted records will be ignored when querying
db.Where("age = 20").Find(&user)
// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
但是使用gorm.DeletedAt
,也会有很多其他字段。每个字段各有不同。后面的章节会详细讲。
如果并不想嵌套gorm.Model。可以这么做。
type User struct {
ID int
Deleted gorm.DeletedAt
Name string
}
你可以使用Unscoped来查询到被软删除的记录。
db.Unscoped().Where("age = 20").Find(&users)
// SELECT * FROM users WHERE age = 20;
你可以使用 Unscoped来永久删除匹配的记录。
db.Unscoped().Delete(&order)
// DELETE FROM orders WHERE id=10;
默认情况下,gorm.Model
使用*time.Time
作为DeletedAt
的字段类型。
不过软删除插件gorm.io/plugin/soft_delete
同时也提供其他的数据格式支持。
注意
当使用DeletedAt
创建唯一复合索引时,你必须使用其他的数据类型,例如通过gorm.io/plugin/soft_delete
插件将字段类型定义为unix时间戳
等等
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"`
}