GORM Standards
Database Connection
import (
"gorm.io/gorm"
"gorm.io/driver/postgres"
)
func InitDB() (*gorm.DB, error) {
dsn := "host=localhost user=postgres password=pass dbname=app port=5432 sslmode=disable"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
Logger: logger.Default.LogMode(logger.Info),
})
if err != nil {
return nil, err
}
sqlDB, _ := db.DB()
sqlDB.SetMaxIdleConns(10)
sqlDB.SetMaxOpenConns(100)
sqlDB.SetConnMaxLifetime(time.Hour)
return db, nil
}
Models
type User struct {
gorm.Model
Name string `gorm:"size:100;not null"`
Email string `gorm:"uniqueIndex;not null"`
Age int `gorm:"default:0"`
Profile Profile `gorm:"constraint:OnDelete:CASCADE;"`
Posts []Post `gorm:"foreignKey:AuthorID"`
}
type Profile struct {
ID uint
UserID uint `gorm:"uniqueIndex"`
Bio string `gorm:"type:text"`
}
type Post struct {
ID uint
Title string
AuthorID uint
Author User `gorm:"foreignKey:AuthorID"`
}
CRUD Operations
user := User{Name: "John", Email: "john@example.com"}
result := db.Create(&user)
users := []User{{Name: "A"}, {Name: "B"}, {Name: "C"}}
db.CreateInBatches(users, 100)
var user User
db.First(&user, 1)
db.First(&user, "email = ?", "john@example.com")
db.Where("age > ?", 18).Find(&users)
db.Model(&user).Update("Name", "Jane")
db.Model(&user).Updates(User{Name: "Jane", Age: 25})
db.Model(&user).Updates(map[string]interface{}{"name": "Jane", "age": 25})
db.Delete(&user, 1)
db.Unscoped().Delete(&user, 1)
Queries
db.Where("name = ?", "John").Find(&users)
db.Where("name IN ?", []string{"John", "Jane"}).Find(&users)
db.Where("age BETWEEN ? AND ?", 18, 65).Find(&users)
db.Order("created_at desc").Limit(10).Offset(20).Find(&users)
db.Select("name", "email").Find(&users)
db.Model(&User{}).Select("name, sum(age)").Group("name").Having("sum(age) > ?", 100).Find(&results)
db.Joins("Profile").Find(&users)
db.Raw("SELECT * FROM users WHERE age > ?", 18).Scan(&users)
Associations
db.Preload("Posts").Find(&users)
db.Preload("Posts.Comments").Find(&users)
db.Preload("Posts", "published = ?", true).Find(&users)
db.Model(&user).Association("Posts").Append(&post)
db.Model(&user).Association("Posts").Delete(&post)
db.Model(&user).Association("Posts").Clear()
db.Model(&user).Association("Posts").Count()
Transactions
err := db.Transaction(func(tx *gorm.DB) error {
if err := tx.Create(&user).Error; err != nil {
return err
}
if err := tx.Create(&profile).Error; err != nil {
return err
}
return nil
})
tx := db.Begin()
if err := tx.Create(&user).Error; err != nil {
tx.Rollback()
return err
}
if err := tx.Create(&profile).Error; err != nil {
tx.Rollback()
return err
}
tx.Commit()
Hooks
func (u *User) BeforeCreate(tx *gorm.DB) error {
u.UUID = uuid.New()
return nil
}
func (u *User) AfterCreate(tx *gorm.DB) error {
return nil
}
Migrations
db.AutoMigrate(&User{}, &Post{}, &Profile{})
Best Practices
- Avoid N+1: Use
Preload or Joins for associations
- Transactions: Wrap related operations in transactions
- Indexes: Add
gorm:"index" for frequently queried columns
- Soft delete: Use
gorm.Model for soft delete, Unscoped() for hard delete
- Migrations: Use migration tools for production, not AutoMigrate