CRUD: Reading and Writing Data

Create

Create Record

  1. user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}
  2. db.NewRecord(user) // => returns `true` as primary key is blank
  3. db.Create(&user)
  4. db.NewRecord(user) // => return `false` after `user` created

Default Values

You could define default value in the gorm tag, then the inserting SQL will ignore these fields that has default value and its value is blank, and after insert the record into database, gorm will load those fields’s value from database.

  1. type Animal struct {
  2. ID int64
  3. Name string `gorm:"default:'galeone'"`
  4. Age int64
  5. }
  6. var animal = Animal{Age: 99, Name: ""}
  7. db.Create(&animal)
  8. // INSERT INTO animals("age") values('99');
  9. // SELECT name from animals WHERE ID=111; // the returning primary key is 111
  10. // animal.Name => 'galeone'

Setting Primary Key In Callbacks

If you want to set primary field’s value in BeforeCreate callback, you could use scope.SetColumn, for example:

  1. func (user *User) BeforeCreate(scope *gorm.Scope) error {
  2. scope.SetColumn("ID", uuid.New())
  3. return nil
  4. }

Extra Creating option

  1. // Add extra SQL option for inserting SQL
  2. db.Set("gorm:insert_option", "ON CONFLICT").Create(&product)
  3. // INSERT INTO products (name, code) VALUES ("name", "code") ON CONFLICT;

Query

  1. // Get first record, order by primary key
  2. db.First(&user)
  3. //// SELECT * FROM users ORDER BY id LIMIT 1;
  4. // Get last record, order by primary key
  5. db.Last(&user)
  6. //// SELECT * FROM users ORDER BY id DESC LIMIT 1;
  7. // Get all records
  8. db.Find(&users)
  9. //// SELECT * FROM users;
  10. // Get record with primary key (only works for integer primary key)
  11. db.First(&user, 10)
  12. //// SELECT * FROM users WHERE id = 10;

Query With Where (Plain SQL)

  1. // Get first matched record
  2. db.Where("name = ?", "jinzhu").First(&user)
  3. //// SELECT * FROM users WHERE name = 'jinzhu' limit 1;
  4. // Get all matched records
  5. db.Where("name = ?", "jinzhu").Find(&users)
  6. //// SELECT * FROM users WHERE name = 'jinzhu';
  7. db.Where("name <> ?", "jinzhu").Find(&users)
  8. // IN
  9. db.Where("name in (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)
  10. // LIKE
  11. db.Where("name LIKE ?", "%jin%").Find(&users)
  12. // AND
  13. db.Where("name = ? AND age >= ?", "jinzhu", "22").Find(&users)
  14. // Time
  15. db.Where("updated_at > ?", lastWeek).Find(&users)
  16. db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)

Query With Where (Struct & Map)

NOTE When query with struct, GORM will only query with those fields has value

  1. // Struct
  2. db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
  3. //// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;
  4. // Map
  5. db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
  6. //// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;
  7. // Slice of primary keys
  8. db.Where([]int64{20, 21, 22}).Find(&users)
  9. //// SELECT * FROM users WHERE id IN (20, 21, 22);

Query With Not

  1. db.Not("name", "jinzhu").First(&user)
  2. //// SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;
  3. // Not In
  4. db.Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&users)
  5. //// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");
  6. // Not In slice of primary keys
  7. db.Not([]int64{1,2,3}).First(&user)
  8. //// SELECT * FROM users WHERE id NOT IN (1,2,3);
  9. db.Not([]int64{}).First(&user)
  10. //// SELECT * FROM users;
  11. // Plain SQL
  12. db.Not("name = ?", "jinzhu").First(&user)
  13. //// SELECT * FROM users WHERE NOT(name = "jinzhu");
  14. // Struct
  15. db.Not(User{Name: "jinzhu"}).First(&user)
  16. //// SELECT * FROM users WHERE name <> "jinzhu";

Query With Inline Condition

NOTE When query with primary key, you should carefully check the value you passed is a valid primary key, to avoid SQL injection

  1. // Get by primary key (only works for integer primary key)
  2. db.First(&user, 23)
  3. //// SELECT * FROM users WHERE id = 23 LIMIT 1;
  4. // Get by primary key if it were a non-integer type
  5. db.First(&user, "id = ?", "string_primary_key")
  6. //// SELECT * FROM users WHERE id = 'string_primary_key' LIMIT 1;
  7. // Plain SQL
  8. db.Find(&user, "name = ?", "jinzhu")
  9. //// SELECT * FROM users WHERE name = "jinzhu";
  10. db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20)
  11. //// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;
  12. // Struct
  13. db.Find(&users, User{Age: 20})
  14. //// SELECT * FROM users WHERE age = 20;
  15. // Map
  16. db.Find(&users, map[string]interface{}{"age": 20})
  17. //// SELECT * FROM users WHERE age = 20;

Query With Or

  1. db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
  2. //// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';
  3. // Struct
  4. db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users)
  5. //// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';
  6. // Map
  7. db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users)

Query Chains

Gorm has a chainable API, you could use it like this

  1. db.Where("name <> ?","jinzhu").Where("age >= ? and role <> ?",20,"admin").Find(&users)
  2. //// SELECT * FROM users WHERE name <> 'jinzhu' AND age >= 20 AND role <> 'admin';
  3. db.Where("role = ?", "admin").Or("role = ?", "super_admin").Not("name = ?", "jinzhu").Find(&users)

SubQuery

  1. db.Where("amount > ?", DB.Table("orders").Select("AVG(amount)").Where("state = ?", "paid").QueryExpr()).Find(&orders)
  2. // SELECT * FROM "orders" WHERE "orders"."deleted_at" IS NULL AND (amount > (SELECT AVG(amount) FROM "orders" WHERE (state = 'paid')));

Extra Querying option

  1. // Add extra SQL option for selecting SQL
  2. db.Set("gorm:query_option", "FOR UPDATE").First(&user, 10)
  3. //// SELECT * FROM users WHERE id = 10 FOR UPDATE;

FirstOrInit

Get first matched record, or initalize a new one with given conditions (only works with struct, map conditions)

  1. // Unfound
  2. db.FirstOrInit(&user, User{Name: "non_existing"})
  3. //// user -> User{Name: "non_existing"}
  4. // Found
  5. db.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)
  6. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
  7. db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
  8. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}

Attrs

Initalize struct with argument if record haven’t been found

  1. // Unfound
  2. db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)
  3. //// SELECT * FROM USERS WHERE name = 'non_existing';
  4. //// user -> User{Name: "non_existing", Age: 20}
  5. db.Where(User{Name: "non_existing"}).Attrs("age", 20).FirstOrInit(&user)
  6. //// SELECT * FROM USERS WHERE name = 'non_existing';
  7. //// user -> User{Name: "non_existing", Age: 20}
  8. // Found
  9. db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)
  10. //// SELECT * FROM USERS WHERE name = jinzhu';
  11. //// user -> User{Id: 111, Name: "Jinzhu", Age: 20}

Assign

Assign argument to results regardless it is found or not

  1. // Unfound
  2. db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
  3. //// user -> User{Name: "non_existing", Age: 20}
  4. // Found
  5. db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)
  6. //// SELECT * FROM USERS WHERE name = jinzhu';
  7. //// user -> User{Id: 111, Name: "Jinzhu", Age: 30}

FirstOrCreate

Get first matched record, or create a new one with given conditions (only works with struct, map conditions)

  1. // Unfound
  2. db.FirstOrCreate(&user, User{Name: "non_existing"})
  3. //// INSERT INTO "users" (name) VALUES ("non_existing");
  4. //// user -> User{Id: 112, Name: "non_existing"}
  5. // Found
  6. db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
  7. //// user -> User{Id: 111, Name: "Jinzhu"}

Attrs

Assgin struct with argument if record haven’t been found

  1. // Unfound
  2. db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
  3. //// SELECT * FROM users WHERE name = 'non_existing';
  4. //// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
  5. //// user -> User{Id: 112, Name: "non_existing", Age: 20}
  6. // Found
  7. db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
  8. //// SELECT * FROM users WHERE name = 'jinzhu';
  9. //// user -> User{Id: 111, Name: "jinzhu", Age: 20}

Assign

Assign it to the record regardless it is found or not, and save back to database.

  1. // Unfound
  2. db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
  3. //// SELECT * FROM users WHERE name = 'non_existing';
  4. //// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
  5. //// user -> User{Id: 112, Name: "non_existing", Age: 20}
  6. // Found
  7. db.Where(User{Name: "jinzhu"}).Assign(User{Age: 30}).FirstOrCreate(&user)
  8. //// SELECT * FROM users WHERE name = 'jinzhu';
  9. //// UPDATE users SET age=30 WHERE id = 111;
  10. //// user -> User{Id: 111, Name: "jinzhu", Age: 30}

Select

Specify fields that you want to retrieve from database, by default, will select all fields;

  1. db.Select("name, age").Find(&users)
  2. //// SELECT name, age FROM users;
  3. db.Select([]string{"name", "age"}).Find(&users)
  4. //// SELECT name, age FROM users;
  5. db.Table("users").Select("COALESCE(age,?)", 42).Rows()
  6. //// SELECT COALESCE(age,'42') FROM users;

Order

Specify order when retrieve records from database, set reorder to true to overwrite defined conditions

  1. db.Order("age desc, name").Find(&users)
  2. //// SELECT * FROM users ORDER BY age desc, name;
  3. // Multiple orders
  4. db.Order("age desc").Order("name").Find(&users)
  5. //// SELECT * FROM users ORDER BY age desc, name;
  6. // ReOrder
  7. db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
  8. //// SELECT * FROM users ORDER BY age desc; (users1)
  9. //// SELECT * FROM users ORDER BY age; (users2)

Limit

Specify the number of records to be retrieved

  1. db.Limit(3).Find(&users)
  2. //// SELECT * FROM users LIMIT 3;
  3. // Cancel limit condition with -1
  4. db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
  5. //// SELECT * FROM users LIMIT 10; (users1)
  6. //// SELECT * FROM users; (users2)

Offset

Specify the number of records to skip before starting to return the records

  1. db.Offset(3).Find(&users)
  2. //// SELECT * FROM users OFFSET 3;
  3. // Cancel offset condition with -1
  4. db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
  5. //// SELECT * FROM users OFFSET 10; (users1)
  6. //// SELECT * FROM users; (users2)

Count

Get how many records for a model

  1. db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
  2. //// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)
  3. //// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)
  4. db.Model(&User{}).Where("name = ?", "jinzhu").Count(&count)
  5. //// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)
  6. db.Table("deleted_users").Count(&count)
  7. //// SELECT count(*) FROM deleted_users;

Group & Having

  1. rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
  2. for rows.Next() {
  3. ...
  4. }
  5. rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
  6. for rows.Next() {
  7. ...
  8. }
  9. type Result struct {
  10. Date time.Time
  11. Total int64
  12. }
  13. db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)

Joins

Specify Joins conditions

  1. rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
  2. for rows.Next() {
  3. ...
  4. }
  5. db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)
  6. // multiple joins with parameter
  7. db.Joins("JOIN emails ON emails.user_id = users.id AND emails.email = ?", "jinzhu@example.org").Joins("JOIN credit_cards ON credit_cards.user_id = users.id").Where("credit_cards.number = ?", "411111111111").Find(&user)

Pluck

Query single column from a model as a map, if you want to query multiple columns, you could use Scan

  1. var ages []int64
  2. db.Find(&users).Pluck("age", &ages)
  3. var names []string
  4. db.Model(&User{}).Pluck("name", &names)
  5. db.Table("deleted_users").Pluck("name", &names)
  6. // Requesting more than one column? Do it like this:
  7. db.Select("name, age").Find(&users)

Scan

Scan results into another struct.

  1. type Result struct {
  2. Name string
  3. Age int
  4. }
  5. var result Result
  6. db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)
  7. // Raw SQL
  8. db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)

Scopes

Pass current database connection to func(*DB) *DB, which could be used to add conditions dynamically

  1. func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
  2. return db.Where("amount > ?", 1000)
  3. }
  4. func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
  5. return db.Where("pay_mode_sign = ?", "C")
  6. }
  7. func PaidWithCod(db *gorm.DB) *gorm.DB {
  8. return db.Where("pay_mode_sign = ?", "C")
  9. }
  10. func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
  11. return func (db *gorm.DB) *gorm.DB {
  12. return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
  13. }
  14. }
  15. db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
  16. // Find all credit card orders and amount greater than 1000
  17. db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
  18. // Find all COD orders and amount greater than 1000
  19. db.Scopes(OrderStatus([]string{"paid", "shipped"})).Find(&orders)
  20. // Find all paid, shipped orders

Specifying The Table Name

  1. // Create `deleted_users` table with struct User's definition
  2. db.Table("deleted_users").CreateTable(&User{})
  3. var deleted_users []User
  4. db.Table("deleted_users").Find(&deleted_users)
  5. //// SELECT * FROM deleted_users;
  6. db.Table("deleted_users").Where("name = ?", "jinzhu").Delete()
  7. //// DELETE FROM deleted_users WHERE name = 'jinzhu';

Preloading (Eager loading)

  1. db.Preload("Orders").Find(&users)
  2. //// SELECT * FROM users;
  3. //// SELECT * FROM orders WHERE user_id IN (1,2,3,4);
  4. db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
  5. //// SELECT * FROM users;
  6. //// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');
  7. db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
  8. //// SELECT * FROM users WHERE state = 'active';
  9. //// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');
  10. db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
  11. //// SELECT * FROM users;
  12. //// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
  13. //// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
  14. //// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to

Custom Preloading SQL

You could custom preloading SQL by passing in func(db *gorm.DB) *gorm.DB (same type as the one used for Scopes), for example:

  1. db.Preload("Orders", func(db *gorm.DB) *gorm.DB {
  2. return db.Order("orders.amount DESC")
  3. }).Find(&users)
  4. //// SELECT * FROM users;
  5. //// SELECT * FROM orders WHERE user_id IN (1,2,3,4) order by orders.amount DESC;

Nested Preloading

  1. db.Preload("Orders.OrderItems").Find(&users)
  2. db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)

Update

Update All Fields

Save will include all fields when perform the Updating SQL, even it is not changed

  1. db.First(&user)
  2. user.Name = "jinzhu 2"
  3. user.Age = 100
  4. db.Save(&user)
  5. //// UPDATE users SET name='jinzhu 2', age=100, birthday='2016-01-01', updated_at = '2013-11-17 21:34:10' WHERE id=111;

Update Changed Fields

If you only want to update changed Fields, you could use Update, Updates

  1. // Update single attribute if it is changed
  2. db.Model(&user).Update("name", "hello")
  3. //// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111;
  4. // Update single attribute with combined conditions
  5. db.Model(&user).Where("active = ?", true).Update("name", "hello")
  6. //// UPDATE users SET name='hello', updated_at='2013-11-17 21:34:10' WHERE id=111 AND active=true;
  7. // Update multiple attributes with `map`, will only update those changed fields
  8. db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})
  9. //// UPDATE users SET name='hello', age=18, actived=false, updated_at='2013-11-17 21:34:10' WHERE id=111;
  10. // Update multiple attributes with `struct`, will only update those changed & non blank fields
  11. db.Model(&user).Updates(User{Name: "hello", Age: 18})
  12. //// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
  13. // WARNING when update with struct, GORM will only update those fields that with non blank value
  14. // For below Update, nothing will be updated as "", 0, false are blank values of their types
  15. db.Model(&user).Updates(User{Name: "", Age: 0, Actived: false})

Update Selected Fields

If you only want to update or ignore some fields when updating, you could use Select, Omit

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

Update Changed Fields Without Callbacks

Above updating operations will perform the model’s BeforeUpdate, AfterUpdate method, update its UpdatedAt timestamp, save its Associations when updaing, if you don’t want to call them, you could use UpdateColumn, UpdateColumns

  1. // Update single attribute, similar with `Update`
  2. db.Model(&user).UpdateColumn("name", "hello")
  3. //// UPDATE users SET name='hello' WHERE id = 111;
  4. // Update multiple attributes, similar with `Updates`
  5. db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
  6. //// UPDATE users SET name='hello', age=18 WHERE id = 111;

Batch Updates

Callbacks won’t run when do batch updates

  1. db.Table("users").Where("id IN (?)", []int{10, 11}).Updates(map[string]interface{}{"name": "hello", "age": 18})
  2. //// UPDATE users SET name='hello', age=18 WHERE id IN (10, 11);
  3. // Update with struct only works with none zero values, or use map[string]interface{}
  4. db.Model(User{}).Updates(User{Name: "hello", Age: 18})
  5. //// UPDATE users SET name='hello', age=18;
  6. // Get updated records count with `RowsAffected`
  7. db.Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected

Update with SQL Expression

  1. DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
  2. //// UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';
  3. DB.Model(&product).Updates(map[string]interface{}{"price": gorm.Expr("price * ? + ?", 2, 100)})
  4. //// UPDATE "products" SET "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';
  5. DB.Model(&product).UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
  6. //// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2';
  7. DB.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
  8. //// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2' AND quantity > 1;

Change Updating Values In Callbacks

If you want to change updating values in callbacks using BeforeUpdate, BeforeSave, you could use scope.SetColumn, for example:

  1. func (user *User) BeforeSave(scope *gorm.Scope) (err error) {
  2. if pw, err := bcrypt.GenerateFromPassword(user.Password, 0); err == nil {
  3. scope.SetColumn("EncryptedPassword", pw)
  4. }
  5. }

Extra Updating option

  1. // Add extra SQL option for updating SQL
  2. db.Model(&user).Set("gorm:update_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Update("name, "hello")
  3. //// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 OPTION (OPTIMIZE FOR UNKNOWN);

Delete

WARNING When delete a record, you need to ensure it’s primary field has value, and GORM will use the primary key to delete the record, if primary field’s blank, GORM will delete all records for the model

  1. // Delete an existing record
  2. db.Delete(&email)
  3. //// DELETE from emails where id=10;
  4. // Add extra SQL option for deleting SQL
  5. db.Set("gorm:delete_option", "OPTION (OPTIMIZE FOR UNKNOWN)").Delete(&email)
  6. //// DELETE from emails where id=10 OPTION (OPTIMIZE FOR UNKNOWN);

Batch Delete

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%";

Soft Delete

If model has DeletedAt field, it will get soft delete ability automatically! then it won’t be deleted from database permanently when call Delete, but only set field DeletedAt‘s value to current time

  1. db.Delete(&user)
  2. //// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;
  3. // Batch Delete
  4. db.Where("age = ?", 20).Delete(&User{})
  5. //// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;
  6. // Soft deleted records will be ignored when query them
  7. db.Where("age = 20").Find(&user)
  8. //// SELECT * FROM users WHERE age = 20 AND deleted_at IS NULL;
  9. // Find soft deleted records with Unscoped
  10. db.Unscoped().Where("age = 20").Find(&users)
  11. //// SELECT * FROM users WHERE age = 20;
  12. // Delete record permanently with Unscoped
  13. db.Unscoped().Delete(&order)
  14. //// DELETE FROM orders WHERE id=10;

Associations

By default when creating/updating a record, GORM will save its associations, if the association has primary key, GORM will call Update to save it, otherwise it will be created.

  1. user := User{
  2. Name: "jinzhu",
  3. BillingAddress: Address{Address1: "Billing Address - Address 1"},
  4. ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
  5. Emails: []Email{
  6. {Email: "jinzhu@example.com"},
  7. {Email: "jinzhu-2@example@example.com"},
  8. },
  9. Languages: []Language{
  10. {Name: "ZH"},
  11. {Name: "EN"},
  12. },
  13. }
  14. db.Create(&user)
  15. //// BEGIN TRANSACTION;
  16. //// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1");
  17. //// INSERT INTO "addresses" (address1) VALUES ("Shipping Address - Address 1");
  18. //// INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
  19. //// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com");
  20. //// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com");
  21. //// INSERT INTO "languages" ("name") VALUES ('ZH');
  22. //// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 1);
  23. //// INSERT INTO "languages" ("name") VALUES ('EN');
  24. //// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2);
  25. //// COMMIT;
  26. db.Save(&user)

Refer Associations for more details

Skip Save Associations when creating/updating

By default when saving an record, GORM will save its associations also, you could skip it by set gorm:save_associations to false

  1. db.Set("gorm:save_associations", false).Create(&user)
  2. db.Set("gorm:save_associations", false).Save(&user)

Skip Save Associations by Tag

You could use Tag to config your struct to never save an association when creating/updating

  1. type User struct {
  2. gorm.Model
  3. Name string
  4. CompanyID uint
  5. Company Company `gorm:"save_associations:false"`
  6. }
  7. type Company struct {
  8. gorm.Model
  9. Name string
  10. }