Getting Started with GORM in Go Applications

Database Initialization

Import the primary library and the specific database driver before establishing a connection.

go get -u gorm.io/gorm
go get -u gorm.io/driver/mysql

Configure the Data Source Name (DSN) and instantiate the client. The configuration object allows customization of naming conventions and other behaviors.

import (
    "log"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
    "gorm.io/gorm/schema"
)

connConfig := "user:password@tcp(localhost:3306)/target_db?charset=utf8mb4&parseTime=True&loc=Local"

databaseClient, err := gorm.Open(mysql.Open(connConfig), &gorm.Config{
    NamingStrategy: schema.NamingStrategy{SingularTable: true},
})
if err != nil {
    log.Fatalf("Database initialization failed: %v", err)
}

Model Definitions and Table Binding

Define Go structs to map directly to relational tables. By default, GORM uses the pluralized type name. You can explicitly specify a tible name via the Table method or struct tags.

type AccountRecord struct {
    ID       uint
    Email    string
    FullName string
    AgeGroup int
}

var records []AccountRecord
var fetchedData []AccountRecord

// Query using an explicit table identifier
databaseClient.Table("account_profiles").Where("full_name = ?", "Alice").Find(&fetchedData)

// Query using the bound model struct
databaseClient.Model(&records).Where("full_name = ?", "Bob").Find(&fetchedData)

Result Scanning and Struct Mapping

When retrieving multiple rows, the Scan function maps query results into a target slice. This is particularly useful when you need to transform column names or select a subset of fields into a different data structure.

type RawSource struct {
    UserID       uint
    ContactEmail string
    DisplayName  string
    AgeRange     int
}

type ViewPayload struct {
    Nickname string
    Category int
}

var sources []RawSource
var payload []ViewPayload

// Execute query and map directly to a secondary structure
databaseClient.Where("age_range > 18 OR contact_email LIKE ?", "%@domain.com").Find(&sources).Scan(&payload)

If the target struct field names differ from the SQL column aliases, utilize the gorm tag to define explicit mappings.

type ViewPayload struct {
    Nickname string `gorm:"column:display_name"`
    Category int
}

Ordering Results

Apply sorting directives using the Order clause. Append ASC for ascending sequences or DESC for descending arrangements.

// Highest values first
databaseClient.Order("age_range DESC").Find(&sources)

// Lowest values first
databaseClient.Order("contact_email ASC").Find(&sources)

Eager Loading Associations

Retreive related entities alongside the primary record using Preload. This prevents the N+1 query problem by joining associated data in a single pass.

type Author struct {
    ID    uint
    Name  string
    Books []Book `gorm:"foreignKey:AuthorID"`
}

func loadWithContext(client *gorm.DB) {
    var writer Author
    client.Preload("Books").First(&writer)
    fmt.Printf("%+v\n", writer)
}

Pagination Implementation

Control result set size by combining Limit and Offset. Calculate the skip amount based on zero-indexed page numbers.

chunkSize := 5
pageNumber := 2
skipAmount := (pageNumber - 1) * chunkSize

var pageResults []AccountRecord
databaseClient.Limit(chunkSize).Offset(skipAmount).Find(&pageResults)

Subquery Construction

Embed internal queries within filter clauses using parentheses. The inner query executes first, providing dynamic threshold values.

type Product struct {
    SKU   uint
    Price int
}

var expensiveProducts []Product
databaseClient.Model(&Product{}).
    Where("price > (?)", databaseClient.Model(&Product{}).Select("AVG(price)"))
    .Find(&expensiveProducts)

Filtering Techniques

Exact Match and Negation

Standard equality checks, exclusion filters, and list-based searches are handled efficiently.

var matched []AccountRecord

// Standard lookup
databaseClient.Find(&matched, "full_name = ?", "Charlie")

// Exclusion pattern
databaseClient.Not("full_name = ?", "Charlie").Find(&matched)

// Row modification counter
affectedRows := databaseClient.Not("full_name = ?", "Charlie").Delete(&matched)
fmt.Println(affectedRows.RowsAffected)

// Multi-value inclusion
databaseClient.Where("full_name IN ?", []string{"David", "Eva"}).Find(&matched)

Pattern Matching and Compound Conditions

Utilize wildcard operators for string searches and chain boolean operators for complex filters.

// Prefix search
databaseClient.Where("full_name LIKE ?", "A%").Find(&matched)

// Fixed-length prefix (matches two characters)
databaseClient.Where("full_name LIKE ?", "B_").Find(&matched)

// Conjunction (AND)
databaseClient.Where("age_range > 25 AND full_name LIKE ?", "%Corp").Find(&matched)
// Equivalent chained approach
databaseClient.Where("age_range > 25").Where("full_name LIKE ?", "%Inc").Find(&matched)

// Disjunction (OR)
databaseClient.Where("age_range < 20 OR full_name LIKE ?", "%Admin").Find(&matched)
// Equivalent chained approach
databaseClient.Where("age_range < 20").Or("full_name LIKE ?", "%Super").Find(&matched)

Managing One-to-Many Relationships

GORM distinguishes between owning and belonging to an entity. Foreign keys can be customized via struct tags to reflect schema requirements.

type Publisher struct {
    PubID   uint
    Brand   string
    Titles  []Edition `gorm:"foreignKey:PubID"`
}

type Edition struct {
    ISBN   uint
    Cover  string
    PubID  uint
    Source Publisher `gorm:"foreignKey:PubID"`
}

Insert nested collections atomically to create both parent and child records in a single transaction.

vol1 := Edition{Cover: "Hardbound"}
vol2 := Edition{Cover: "Paperback"}
publishingHouse := Publisher{Brand: "Academic Press", Titles: []Edition{vol1, vol2}}

databaseClient.Debug().Create(&publishingHouse)

Asssociate new children with pre-existing parents by referencing the external identifier or fetching the parent record first.

databaseClient.Create(&Edition{
    Cover: "Special Release",
    PubID: 999,
})

// Alternative: resolve parent dynamically
var activePublisher Publisher
databaseClient.First(&activePublisher, "pub_id = ?", 102)
databaseClient.Create(&Edition{Cover: "Upcoming", PubID: activePublisher.PubID})

Tags: Go GORM database sql ORM

Posted on Wed, 02 Sep 2026 16:31:55 +0000 by Tchelo