Skip to content

Golang ORM框架Ent一文速通

Ent 是由 Meta(原 Facebook)开发的 Go 语言 ORM 框架,专注于实体关系建模和代码生成,以类型安全、高性能和简洁的 API 著称。与传统 ORM 依赖反射不同,Ent 基于代码生成机制,在编译期生成类型安全的数据库操作代码,避免了运行时反射的性能损耗,同时提供了清晰的实体关系管理能力。

核心特性

  • 类型安全:通过代码生成确保所有数据库操作(查询、更新等)在编译期校验,避免运行时类型错误。
  • 实体关系支持:原生支持一对一、一对多、多对多等复杂关系,关系定义直观。
  • 自动迁移:内置数据库迁移工具,可自动生成和执行 schema 变更 SQL(无需手动写 DDL)。
  • 流畅查询 API:提供链式调用的查询接口,语法简洁易读(类似 WHERE ... AND ... ORDER BY 的自然映射)。
  • 多数据库支持:兼容 MySQL、PostgreSQL、SQLite、MariaDB 等主流数据库。
  • 扩展性:支持自定义钩子(Hooks)、索引、事务等高级特性。

快速上手

简单写一个CRUD的小例子,方便我们快速上手:

1、环境准备和安装

  1. 创建项目并初始化Gomokuai
bash
mkdir ent-demo && cd ent-demo
go mod init ent-demo  # 初始化模块(模块名自定义)
  1. 安装Ent
bash
go get entgo.io/ent@latest  # 安装最新版本
  1. 使用Ent命令行工具创建实体
bash
# 创建 User 实体(会生成 ent/schema/user.go)
go run -mod=mod entgo.io/ent/cmd/ent new User
  1. 定义实体结构(schema/user.go)
go
// Fields of the User.
func (User) Fields() []ent.Field {
	return []ent.Field{
		field.String("name").Default("unknown"),
		field.Int("age"),
	}
}
  1. 使用go generate生成代码
bash
go generate ./ent

生成结构:

ent
├── client.go
├── config.go
├── context.go
├── ent.go
├── generate.go
├── mutation.go
... truncated
├── schema
│   └── user.go
├── tx.go
├── user
│   ├── user.go
│   └── where.go
├── user.go
├── user_create.go
├── user_delete.go
├── user_query.go
└── user_update.go
  1. 数据库连接和CRUD操作示例:
go
package main

import (
	"context"
	"ent_demo/ent"
	"ent_demo/ent/user"
	"log"

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

func main() {
	client, err := ent.Open("sqlite3", "file:ent?mode=memory&cache=shared&_fk=1")
	if err != nil {
		panic(err)
	}
	defer client.Close()

	ctx := context.Background()
	if err := client.Schema.Create(ctx); err != nil {
		log.Fatalf("failed creating schema resources: %v", err)
	}

	_, err = CreateUser(ctx, client)
	if err != nil {
		log.Fatalf("failed creating user: %v", err)
	}

	_, err = QueryUser(ctx, client)
	if err != nil {
		log.Fatalf("failed querying user: %v", err)
	}

	_, err = UpdateUser(ctx, client)
	if err != nil {
		log.Fatalf("failed querying user: %v", err)
	}

	_, err = QueryUser(ctx, client)
	if err != nil {
		log.Fatalf("failed querying user: %v", err)
	}

	_, err = DeleteUser(ctx, client)
	if err != nil {
		log.Fatalf("failed querying user: %v", err)
	}
}

func CreateUser(ctx context.Context, client *ent.Client) (*ent.User, error) {
	u, err := client.User.
		Create().
		SetName("James").
		SetAge(19).
		Save(ctx)
	if err != nil {
		return nil, err
	}

	log.Println("User is Created:", u)
	return u, nil
}

func QueryUser(ctx context.Context, client *ent.Client) (*ent.User, error) {
	u, err := client.User.
		Query().
		Where(user.Name("James")).
		Only(ctx)

	if err != nil {
		return nil, err
	}

	log.Println("User returned:", u)
	return u, nil
}

func UpdateUser(ctx context.Context, client *ent.Client) (int, error) {
	u, err := client.User.
		Update().
		Where(user.Name("James")).
		SetAge(20).
		Save(ctx)
	if err != nil {
		return 0, err
	}

	log.Println("User is Updated, affected rows count:", u)
	return u, nil
}

func DeleteUser(ctx context.Context, client *ent.Client) (int, error) {
	u, err := client.User.
		Delete().
		Where(user.Name("James")).
		Exec(ctx)
	if err != nil {
		return 0, err
	}

	log.Println("User is Deleted, affected rows count:", u)
	return u, nil
}

参考