Delete a Record

When deleting a record, the deleted value needs to have primary key or it will trigger a Batch Delete, for example:

  1. // Email's ID is `10`
  2. db.Delete(&email)
  3. // DELETE from emails where id = 10;
  4. // Delete with additional conditions
  5. db.Where("name = ?", "jinzhu").Delete(&email)
  6. // DELETE from emails where id = 10 AND name = "jinzhu";

Delete with primary key

GORM allows to delete objects using primary key(s) with inline condition, it works with numbers, check out Query Inline Conditions for details

  1. db.Delete(&User{}, 10)
  2. // DELETE FROM users WHERE id = 10;
  3. db.Delete(&User{}, "10")
  4. // DELETE FROM users WHERE id = 10;
  5. db.Delete(&users, []int{1,2,3})
  6. // DELETE FROM users WHERE id IN (1,2,3);

Delete Hooks

GORM allows hooks BeforeDelete, AfterDelete, those methods will be called when deleting a record, refer Hooks for details

  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. }

Batch Delete

The specified value has no primary value, GORM will perform a batch delete, it will delete all matched records

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

Block Global Delete

If you perform a batch delete without any conditions, GORM WON’T run it, and will return ErrMissingWhereClause error

You have to use some conditions or use raw SQL or enable AllowGlobalUpdate mode, for example:

  1. db.Delete(&User{}).Error // gorm.ErrMissingWhereClause
  2. db.Where("1 = 1").Delete(&User{})
  3. // DELETE FROM `users` WHERE 1=1
  4. db.Exec("DELETE FROM users")
  5. // DELETE FROM users
  6. db.Session(&gorm.Session{AllowGlobalUpdate: true}).Delete(&User{})
  7. // DELETE FROM users

Returning Data From Deleted Rows

Return deleted data, only works for database support Returning, for example:

  1. // return all columns
  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}}
  6. // return specified columns
  7. DB.Clauses(clause.Returning{Columns: []clause.Column{{Name: "name"}, {Name: "salary"}}}).Where("role = ?", "admin").Delete(&users)
  8. // DELETE FROM `users` WHERE role = "admin" RETURNING `name`, `salary`
  9. // users => []User{{ID: 0, Name: "jinzhu", Role: "", Salary: 100}, {ID: 0, Name: "jinzhu.2", Role: "", Salary: 1000}}

Soft Delete

If your model includes a gorm.DeletedAt field (which is included in gorm.Model), it will get soft delete ability automatically!

When calling Delete, the record WON’T be removed from the database, but GORM will set the DeletedAt‘s value to the current time, and the data is not findable with normal Query methods anymore.

  1. // user's ID is `111`
  2. db.Delete(&user)
  3. // UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
  4. // Batch Delete
  5. db.Where("age = ?", 20).Delete(&User{})
  6. // UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
  7. // Soft deleted records will be ignored when querying
  8. db.Where("age = 20").Find(&user)
  9. // SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;

If you don’t want to include gorm.Model, you can enable the soft delete feature like:

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

Find soft deleted records

You can find soft deleted records with Unscoped

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

Delete permanently

You can delete matched records permanently with Unscoped

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

Delete Flag

Use unix second as delete flag

  1. import "gorm.io/plugin/soft_delete"
  2. type User struct {
  3. ID uint
  4. Name string
  5. DeletedAt soft_delete.DeletedAt
  6. }
  7. // Query
  8. SELECT * FROM users WHERE deleted_at = 0;
  9. // Delete
  10. UPDATE users SET deleted_at = /* current unix second */ WHERE ID = 1;

INFO when using unique field with soft delete, you should create a composite index with the unix second based DeletedAt field, e.g:

  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" }

Use 1 / 0 as delete flag

  1. import "gorm.io/plugin/soft_delete"
  2. type User struct {
  3. ID uint
  4. Name string
  5. IsDel soft_delete.DeletedAt `gorm:"softDelete:flag"`
  6. }
  7. // Query
  8. SELECT * FROM users WHERE is_del = 0;
  9. // Delete
  10. UPDATE users SET is_del = 1 WHERE ID = 1;