or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

associations.mdclause.mddatabase-operations.mdhooks.mdindex.mdlogger.mdmigrations.mdquery-building.mdschema.mdtransactions.md
tile.json

database-operations.mddocs/

Database Operations (CRUD)

This document covers the core Create, Read, Update, and Delete operations in GORM.

Creating Records

Create Single Record

Insert a new record into the database.

func (db *DB) Create(value interface{}) *DB

Usage:

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)

Create in Batches

Insert multiple records in batches to improve performance.

func (db *DB) CreateInBatches(value interface{}, batchSize int) *DB

Usage:

var users = []User{{Name: "Alice"}, {Name: "Bob"}, {Name: "Carol"}}
db.CreateInBatches(users, 100)

Save

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{}) *DB

Usage:

// Insert if ID is zero
user := User{Name: "Alice", Age: 25}
db.Save(&user)

// Update if ID exists
user.Age = 26
db.Save(&user)

Selected Fields on Create

Create with only specific fields.

// Create with selected fields
db.Select("Name", "Age").Create(&user)

// Create omitting specific fields
db.Omit("Age").Create(&user)

Reading Records

Find First Record

Find the first record ordered by primary key.

func (db *DB) First(dest interface{}, conds ...interface{}) *DB

Usage:

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 Last Record

Find the last record ordered by primary key.

func (db *DB) Last(dest interface{}, conds ...interface{}) *DB

Usage:

var user User
db.Last(&user)

Find Record Without Ordering

Find a record without any specific ordering.

func (db *DB) Take(dest interface{}, conds ...interface{}) *DB

Usage:

var user User
db.Take(&user)

Find All Records

Find all records that match the query.

func (db *DB) Find(dest interface{}, conds ...interface{}) *DB

Usage:

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

Find in Batches

Retrieve and process records in batches.

func (db *DB) FindInBatches(dest interface{}, batchSize int, fc func(tx *DB, batch int) error) *DB

Usage:

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

First or Initialize

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{}) *DB

Usage:

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)

First or Create

Get the first matching record or create a new one with given conditions.

func (db *DB) FirstOrCreate(dest interface{}, conds ...interface{}) *DB

Usage:

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)

Attrs and Assign

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{}) *DB

Updating Records

Update Single Column

Update a single column with lifecycle hooks.

func (db *DB) Update(column string, value interface{}) *DB

Usage:

// 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

Update multiple columns with lifecycle hooks.

func (db *DB) Updates(values interface{}) *DB

Usage:

// 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 Without Hooks

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{}) *DB

Usage:

db.Model(&user).UpdateColumn("Age", 26)

db.Model(&user).UpdateColumns(map[string]interface{}{
    "Name": "Alice",
    "Age":  26,
})

Update Selected Fields

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

Batch Updates

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)

Deleting Records

Delete Records

Delete records matching conditions. If the model has a DeletedAt field, it will be soft deleted.

func (db *DB) Delete(value interface{}, conds ...interface{}) *DB

Usage:

// 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{})

Soft Delete

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 records

Permanent Delete

Force permanent deletion even with DeletedAt field.

// Include soft deleted records in query
func (db *DB) Unscoped() *DB

Usage:

// 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 with Associations

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)

Counting Records

Count the number of matching records.

func (db *DB) Count(count *int64) *DB

Usage:

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)

Pluck

Query a single column and scan into a slice.

func (db *DB) Pluck(column string, dest interface{}) *DB

Usage:

var names []string
db.Model(&User{}).Pluck("name", &names)

var ages []int
db.Model(&User{}).Where("age > ?", 18).Pluck("age", &ages)

Working with sql.DB

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()

Error Handling

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
}

Common Error Types

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
)

Advanced Options

Select Specific Fields

// Select specific fields
db.Select("name", "age").Find(&users)

// Select all except specific fields
db.Omit("password").Find(&users)

Map Columns

Map model columns to different database column names.

func (db *DB) MapColumns(m map[string]string) *DB

Usage:

db.Model(&User{}).MapColumns(map[string]string{
    "Name": "user_name",
}).Create(&user)

Pluck Column Values

Query a single column from a model, returning values in a slice.

func (db *DB) Pluck(column string, dest interface{}) *DB

Usage:

var ages []int64
db.Model(&User{}).Pluck("age", &ages)

var names []string
db.Model(&User{}).Pluck("name", &names)

Connection Pooling

Execute operations with a dedicated database connection.

func (db *DB) Connection(fc func(tx *DB) error) error

Usage:

// Use a dedicated connection for multiple operations
db.Connection(func(tx *DB) error {
    tx.Create(&user1)
    tx.Create(&user2)
    return nil
})

Error Handling

Add errors to the DB error chain.

func (db *DB) AddError(err error) error

Usage:

if err := validateUser(&user); err != nil {
    db.AddError(err)
}