🖥️ VS Code: Lihat Database Langsung dari Editor

Install extension SQLite Viewer (oleh Florian Klampfer) dari Extensions panel. Setelah GORM membuat file app.db (SQLite), kamu bisa klik file tersebut di sidebar VS Code dan melihat isi tabel langsung tanpa perlu tools eksternal. Untuk MySQL/PostgreSQL, coba extension Database Client (oleh cweijan).

GORM adalah ORM paling populer di ekosistem Go. Dengan GORM, kamu bisa berinteraksi dengan database (MySQL, PostgreSQL, SQLite) menggunakan struct Go tanpa menulis SQL manual untuk operasi standar.

Install GORM

# Install GORM
go get gorm.io/gorm

# Install driver database (pilih salah satu)
go get gorm.io/driver/sqlite    # SQLite
go get gorm.io/driver/mysql     # MySQL
go get gorm.io/driver/postgres  # PostgreSQL

Connect ke Database

package main

import (
    "gorm.io/driver/sqlite"
    "gorm.io/driver/mysql"
    "gorm.io/gorm"
)

// SQLite (cocok untuk development/testing)
db, err := gorm.Open(sqlite.Open("app.db"), &gorm.Config{})

// MySQL
dsn := "user:password@tcp(127.0.0.1:3306)/dbname?charset=utf8mb4&parseTime=True"
db, err := gorm.Open(mysql.Open(dsn), &gorm.Config{})

// PostgreSQL
dsn := "host=localhost user=postgres password=secret dbname=mydb port=5432"
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{})

if err != nil {
    panic("Gagal connect ke database: " + err.Error())
}

Definisi Model

type User struct {
    gorm.Model           // embed: ID, CreatedAt, UpdatedAt, DeletedAt (soft delete)
    Nama       string    `gorm:"not null"`
    Email      string    `gorm:"uniqueIndex;not null"`
    Password   string    `gorm:"not null"`
    Aktif      bool      `gorm:"default:true"`
    Orders     []Order   // relasi HasMany
}

type Order struct {
    gorm.Model
    UserID  uint    // foreign key otomatis
    Produk  string  `gorm:"not null"`
    Harga   float64
    User    User    // relasi BelongsTo
}

// gorm.Model memberikan field:
// ID        uint (auto increment primary key)
// CreatedAt time.Time
// UpdatedAt time.Time
// DeletedAt gorm.DeletedAt (soft delete)

AutoMigrate

// Buat/update tabel secara otomatis berdasarkan struct
err := db.AutoMigrate(&User{}, &Order{})
if err != nil {
    panic(err)
}
// AutoMigrate hanya menambah kolom baru, tidak menghapus kolom yang ada

Create

user := User{
    Nama:     "Budi Santoso",
    Email:    "budi@email.com",
    Password: "hashedpassword",
}

result := db.Create(&user)
if result.Error != nil {
    fmt.Println("Error:", result.Error)
}
fmt.Println("ID baru:", user.ID)  // ID terisi otomatis setelah Create

// Insert banyak sekaligus
users := []User{
    {Nama: "Alice", Email: "alice@email.com", Password: "pass1"},
    {Nama: "Bob",   Email: "bob@email.com",   Password: "pass2"},
}
db.Create(&users)

Read

// Ambil satu record — First, Last, Take
var user User
db.First(&user, 1)              // by primary key
db.First(&user, "email = ?", "budi@email.com")

// Ambil semua
var users []User
db.Find(&users)
db.Find(&users, "aktif = ?", true)

// Where
db.Where("nama LIKE ?", "%Budi%").Find(&users)
db.Where("aktif = ? AND umur > ?", true, 20).Find(&users)

// Order, Limit, Offset
db.Order("created_at desc").Limit(10).Offset(0).Find(&users)

// Select kolom tertentu
db.Select("id", "nama", "email").Find(&users)

// Count
var total int64
db.Model(&User{}).Where("aktif = ?", true).Count(&total)

// Cek record tidak ditemukan
result := db.First(&user, 999)
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
    fmt.Println("User tidak ditemukan")
}

Update

// Update satu field
db.Model(&user).Update("nama", "Budi Santoso Jr.")

// Update banyak field dengan struct (zero value diabaikan)
db.Model(&user).Updates(User{Nama: "Nama Baru", Aktif: true})

// Update dengan map (zero value tetap diupdate)
db.Model(&user).Updates(map[string]interface{}{
    "nama":  "Nama Baru",
    "aktif": false,
})

// Update berdasarkan kondisi
db.Model(&User{}).Where("aktif = ?", false).Update("nama", "Inactive User")

Delete (Soft Delete & Hard Delete)

// Soft delete (karena User embed gorm.Model)
// Hanya mengisi DeletedAt, record tidak benar-benar terhapus
db.Delete(&user, 1)

// Query otomatis mengecualikan yang sudah soft-deleted
db.Find(&users)  // tidak termasuk yang deleted

// Temukan yang sudah di-delete
db.Unscoped().Find(&users)

// Hard delete (permanent)
db.Unscoped().Delete(&user, 1)

Relasi

// Preload — eager loading relasi
var user User
db.Preload("Orders").First(&user, 1)
fmt.Println(user.Orders)  // orders sudah terisi

// Preload bersyarat
db.Preload("Orders", "harga > ?", 100000).Find(&users)

// Buat record dengan relasi
user := User{
    Nama:  "Sari",
    Email: "sari@email.com",
    Orders: []Order{
        {Produk: "Laptop", Harga: 15000000},
        {Produk: "Mouse",  Harga: 250000},
    },
}
db.Create(&user)  // user + orders dibuat sekaligus

// Joins (SQL JOIN)
db.Joins("Orders").Find(&users)
💡 Tips GORM

  • Selalu cek result.Error setelah operasi database
  • Gunakan db.Debug() untuk melihat query SQL yang dihasilkan
  • Untuk performa, gunakan Select dan hanya ambil kolom yang dibutuhkan
  • Gunakan transaksi (db.Transaction) untuk operasi multi-step yang harus atomic