This document covers the core Create, Read, Update, and Delete operations in GORM.
Insert a new record into the database.
func (db *DB) Create(value interface{}) *DBUsage:
user := User{Name: "Alice", Age: 25}
result := db.Create(&user)
// Access auto-generated ID
fmt.Println(user.ID)
// Check for errors
if result.Error != nil {
// Handle error
}
// Get rows affected
fmt.Println(result.RowsAffected)Insert multiple records in batches to improve performance.
func (db *DB) CreateInBatches(value interface{}, batchSize int) *DBUsage:
var users = []User{{Name: "Alice"}, {Name: "Bob"}, {Name: "Carol"}}
db.CreateInBatches(users, 100)Save all fields of a record. If the record doesn't have a primary key value, it will insert. Otherwise, it will update all fields.
func (db *DB) Save(value interface{}) *DBUsage:
// Insert if ID is zero
user := User{Name: "Alice", Age: 25}
db.Save(&user)
// Update if ID exists
user.Age = 26
db.Save(&user)Create with only specific fields.
// Create with selected fields
db.Select("Name", "Age").Create(&user)
// Create omitting specific fields
db.Omit("Age").Create(&user)Find the first record ordered by primary key.
func (db *DB) First(dest interface{}, conds ...interface{}) *DBUsage:
var user User
// Find first user
db.First(&user)
// Find first user with conditions (inline conditions)
db.First(&user, 10) // WHERE id = 10
db.First(&user, "name = ?", "Alice") // WHERE name = 'Alice'
// Check if record was found
if errors.Is(db.First(&user).Error, gorm.ErrRecordNotFound) {
// Handle not found
}Find the last record ordered by primary key.
func (db *DB) Last(dest interface{}, conds ...interface{}) *DBUsage:
var user User
db.Last(&user)Find a record without any specific ordering.
func (db *DB) Take(dest interface{}, conds ...interface{}) *DBUsage:
var user User
db.Take(&user)Find all records that match the query.
func (db *DB) Find(dest interface{}, conds ...interface{}) *DBUsage:
var users []User
// Find all users
db.Find(&users)
// Find with conditions
db.Find(&users, "age > ?", 18)
// Find by primary keys
db.Find(&users, []int{1, 2, 3})Retrieve and process records in batches.
func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, batch int) error) *DBUsage:
var users []User
db.FindInBatches(&users, 100, func(tx *DB, batch int) error {
// Process users in this batch
for _, user := range users {
// Process user
}
// Return error to stop batching
return nil
})Get the first matching record or initialize a new instance with search attributes and optional additional attributes.
func (db *DB) FirstOrInit(dest interface{}, conds ...interface{}) *DBUsage:
var user User
// User not found, initialize with given conditions
db.FirstOrInit(&user, User{Name: "Alice"})
// User not found, initialize with given conditions and Attrs
db.Where(User{Name: "Alice"}).Attrs(User{Age: 20}).FirstOrInit(&user)
// User found, Attrs will be ignored
db.Where(User{Name: "Alice"}).Attrs(User{Age: 20}).FirstOrInit(&user)
// Assign attributes regardless of whether record is found
db.Where(User{Name: "Alice"}).Assign(User{Age: 20}).FirstOrInit(&user)Get the first matching record or create a new one with given conditions.
func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) *DBUsage:
var user User
// User not found, create it
db.FirstOrCreate(&user, User{Name: "Alice"})
// User not found, create with Attrs
db.Where(User{Name: "Alice"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
// User found, Attrs will be ignored
db.Where(User{Name: "Alice"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
// Assign attributes regardless of whether record is found (and save)
db.Where(User{Name: "Alice"}).Assign(User{Age: 20}).FirstOrCreate(&user)Specify additional attributes for FirstOrInit/FirstOrCreate.
// Set attributes if record not found
func (db *DB) Attrs(attrs ...interface{}) *DB
// Set attributes regardless of whether record is found
func (db *DB) Assign(attrs ...interface{}) *DBUpdate a single column with lifecycle hooks.
func (db *DB) Update(column string, value interface{}) *DBUsage:
// Update single column for user with id=1
db.Model(&User{}).Where("id = ?", 1).Update("name", "Alice")
// Update with model
db.Model(&user).Update("Age", 26)Update multiple columns with lifecycle hooks.
func (db *DB) Updates(values interface{}) *DBUsage:
// Update with struct (only non-zero fields)
db.Model(&user).Updates(User{Name: "Alice", Age: 26})
// Update with map (all specified fields)
db.Model(&user).Updates(map[string]interface{}{
"Name": "Alice",
"Age": 0, // Will be updated to 0
})
// Update multiple records
db.Model(&User{}).Where("age < ?", 18).Updates(map[string]interface{}{
"Active": false,
})Update columns without triggering lifecycle hooks or updating UpdatedAt.
// Update single column without hooks
func (db *DB) UpdateColumn(column string, value interface{}) *DB
// Update multiple columns without hooks
func (db *DB) UpdateColumns(values interface{}) *DBUsage:
db.Model(&user).UpdateColumn("Age", 26)
db.Model(&user).UpdateColumns(map[string]interface{}{
"Name": "Alice",
"Age": 26,
})Update only specific fields.
// Update selected fields
db.Model(&user).Select("Name").Updates(map[string]interface{}{
"Name": "Alice",
"Age": 26, // Will be ignored
})
// Update all fields except omitted ones
db.Model(&user).Omit("Age").Updates(User{
Name: "Alice",
Age: 26, // Will be ignored
})Update multiple records matching conditions.
// Update with conditions
db.Model(&User{}).Where("active = ?", true).Update("age", 18)
// WARNING: Update without conditions will fail by default
// Enable with AllowGlobalUpdate config or add a WHERE condition
db.Session(&gorm.Session{AllowGlobalUpdate: true}).Model(&User{}).Update("age", 18)Delete records matching conditions. If the model has a DeletedAt field, it will be soft deleted.
func (db *DB) Delete(value interface{}, conds ...interface{}) *DBUsage:
// Delete by primary key
db.Delete(&user)
// Delete with inline conditions
db.Delete(&User{}, 10) // DELETE FROM users WHERE id = 10
db.Delete(&User{}, "name = ?", "Alice") // DELETE FROM users WHERE name = 'Alice'
// Delete with WHERE clause
db.Where("age < ?", 18).Delete(&User{})
// Batch delete
db.Where("email LIKE ?", "%@example.com").Delete(&User{})If your model includes a gorm.DeletedAt field (included in gorm.Model), records will be soft deleted automatically.
type User struct {
ID uint
Name string
DeletedAt gorm.DeletedAt `gorm:"index"`
}
// Soft delete (sets DeletedAt to current time)
db.Delete(&user)
// Query will automatically exclude soft deleted records
db.Find(&users) // Won't include deleted recordsForce permanent deletion even with DeletedAt field.
// Include soft deleted records in query
func (db *DB) Unscoped() *DBUsage:
// Permanently delete
db.Unscoped().Delete(&user)
// Find soft deleted records
db.Unscoped().Find(&users)
// Count all records including soft deleted
db.Unscoped().Model(&User{}).Count(&count)Delete associated records when deleting a record.
// Configure with Select to delete associations
db.Select("Orders").Delete(&user) // Delete user and their orders
// Delete multiple associations
db.Select("Orders", "CreditCards").Delete(&user)
// Delete all associations
db.Select(clause.Associations).Delete(&user)Count the number of matching records.
func (db *DB) Count(count *int64) *DBUsage:
var count int64
// Count all users
db.Model(&User{}).Count(&count)
// Count with conditions
db.Model(&User{}).Where("age > ?", 18).Count(&count)
// Count distinct values
db.Model(&User{}).Distinct("name").Count(&count)Query a single column and scan into a slice.
func (db *DB) Pluck(column string, dest interface{}) *DBUsage:
var names []string
db.Model(&User{}).Pluck("name", &names)
var ages []int
db.Model(&User{}).Where("age > ?", 18).Pluck("age", &ages)Get the underlying database connection.
// Get underlying sql.DB
func (db *DB) DB() (*sql.DB, error)Usage:
sqlDB, err := db.DB()
// Set connection pool settings
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
// Ping database
err = sqlDB.Ping()
// Close database
sqlDB.Close()GORM returns errors through the Error field of the DB instance.
result := db.First(&user)
if result.Error != nil {
// Check for specific errors
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
// Handle not found
} else {
// Handle other errors
}
}
// Chain error handling
if err := db.Create(&user).Error; err != nil {
// Handle error
}import "gorm.io/gorm"
var (
ErrRecordNotFound error // Record not found
ErrInvalidData error // Invalid data
ErrDuplicatedKey error // Unique constraint violation
ErrForeignKeyViolated error // Foreign key constraint violation
)// Select specific fields
db.Select("name", "age").Find(&users)
// Select all except specific fields
db.Omit("password").Find(&users)Map model columns to different database column names.
func (db *DB) MapColumns(m map[string]string) *DBUsage:
db.Model(&User{}).MapColumns(map[string]string{
"Name": "user_name",
}).Create(&user)Query a single column from a model, returning values in a slice.
func (db *DB) Pluck(column string, dest interface{}) *DBUsage:
var ages []int64
db.Model(&User{}).Pluck("age", &ages)
var names []string
db.Model(&User{}).Pluck("name", &names)Execute operations with a dedicated database connection.
func (db *DB) Connection(fc func(tx *DB) error) errorUsage:
// Use a dedicated connection for multiple operations
db.Connection(func(tx *DB) error {
tx.Create(&user1)
tx.Create(&user2)
return nil
})Add errors to the DB error chain.
func (db *DB) AddError(err error) errorUsage:
if err := validateUser(&user); err != nil {
db.AddError(err)
}