ORM для Go (Golang): сравнение и примеры использования

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

ORM для Go (Golang): сравнение и примеры

Разработка на Go (Golang) часто требует взаимодействия с базами данных. Вместо написания сырых SQL-запросов разработчики всё чаще прибегают к ORM (Object-Relational Mapping) — инструментам, которые автоматизируют преобразование данных между реляционной базой и объектами языка. В этой статье мы разберём четыре самые популярные ORM для Go: GORM, Ent, SQLBoiler и Bun. Вы узнаете их сильные и слабые стороны, увидите примеры кода и сможете сделать осознанный выбор для своего проекта.

Зачем нужна ORM в Go?

ORM решает несколько ключевых задач:

  • Сокращение boilerplate-кода — не нужно писать CRUD-операции вручную.
  • Безопасность типов — компилятор Go проверяет соответствие полей структуры столбцам таблицы.
  • Миграции схемы — автоматическое создание и обновление таблиц.
  • Абстракция БД — смена СУБД (PostgreSQL, MySQL, SQLite) без переписывания запросов.

1. GORM — самый популярный выбор

GORM — это де-факто стандарт ORM в экосистеме Go. Он известен своим богатым функционалом: автоматические миграции, хуки, цепочки методов, поддержка транзакций и отношений (Has Many, Belongs To, Many2Many).

Пример кода на GORM

package main

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

type User struct {
    gorm.Model
    Name  string
    Email string `gorm:"uniqueIndex"`
}

func main() {
    db, err := gorm.Open(sqlite.Open("test.db"), &gorm.Config{})
    if err != nil {
        panic("failed to connect database")
    }

    // Автомиграция
    db.AutoMigrate(&User{})

    // Вставка
    db.Create(&User{Name: "Alice", Email: "alice@example.com"})

    // Чтение
    var user User
    db.First(&user, 1) // по первичному ключу
    db.First(&user, "email = ?", "alice@example.com")

    // Обновление
    db.Model(&user).Update("Name", "Bob")

    // Удаление
    db.Delete(&user)
}

Плюсы: огромное сообщество, множество документации, встроенная поддержка ассоциаций и хуков.

Минусы: иногда медленная производительность на сложных запросах, магическое поведение (например, автоматическое изменение полей).

2. Ent — кодогенерация и строгая типизация

Ent от Facebook (Meta) — это не просто ORM, а целый фреймворк для работы с сущностями. Он генерирует Go-код на основе схемы, описанной в Go-синтаксисе. Это даёт максимальную производительность и безопасность типов.

Пример кода на Ent

// schema/user.go
package schema

import (
    "entgo.io/ent"
    "entgo.io/ent/schema/field"
)

type User struct {
    ent.Schema
}

func (User) Fields() []ent.Field {
    return []ent.Field{
        field.String("name"),
        field.String("email").Unique(),
    }
}

// main.go
package main

import (
    "context"
    "log"

    "entgo.io/ent/dialect/sqlite"
    "yourproject/ent"
)

func main() {
    client, err := ent.Open("sqlite3", "file:ent.db?cache=shared&mode=rwc")
    if err != nil {
        log.Fatal(err)
    }
    defer client.Close()

    ctx := context.Background()
    // Создание таблиц
    if err := client.Schema.Create(ctx); err != nil {
        log.Fatal(err)
    }

    // Вставка
    u, _ := client.User.Create().SetName("Alice").SetEmail("alice@example.com").Save(ctx)

    // Чтение
    user, _ := client.User.Get(ctx, u.ID)
    log.Println(user.Name)
}

Плюсы: высокая производительность, полная типизация, отличная поддержка графовых запросов.

Минусы: крутой порог входа, необходимость запускать кодогенерацию, меньше встроенных фич (например, нет хуков).

3. SQLBoiler — генерация на основе схемы БД

SQLBoiler генерирует Go-код на основе существующей базы данных. Он анализирует структуру таблиц и создаёт строго типизированные модели. Это идеальный выбор для проектов, где схема БД уже спроектирована.

Пример кода на SQLBoiler

package main

import (
    "context"
    "database/sql"
    "log"

    _ "github.com/mattn/go-sqlite3"
    "yourproject/models"
)

func main() {
    db, _ := sql                    

Рекомендаций