跳到主要内容

代码生成介绍

安装

本项目有一个代码生成工具叫 ent,运行下面的命令安装 ent

go get entgo.io/ent/cmd/ent

初始化一个新的模式

运行 ent init 生成一个或多个模式模板:

go run -mod=mod entgo.io/ent/cmd/ent new User Pet

init 会在 ent/schema 目录下创建两个模式(user.gopet.go)。 如果 ent 不存在则会被创建。惯例是在项目根目录下设置一个名为 ent 的目录。

生成资产

在添加几个 字段后,需要生成用于处理实体的资产。在项目跟目录运行 ent generate 或 使用 go generate 命令:

go generate ./ent

generate 命令为模式生成如下资产:

  • 用来与图互操作的 ClientTx 对象。
  • 每个模式类型的 CRUD 构建器,查阅 CRUD 获取更多信息。
  • 每个模式类型的实体对象(Go 语言结构体)。
  • 与构建器互操作的包含常量和谓语的包。
  • SQL 方言的 migrate 包,查阅 迁移 了解更多信息。
  • 用来添加突变中间件的 hook 包,查阅 钩子 了解更多信息。

entcent 的版本兼容

当在项目中使用 ent CLI,你需要确保使用的 CLI 版本与项目 ent 版本 完全一致

实现此目标的一种方法是让 go generate 在运行 ent 时使用 go.mod 文件中指定的版本。 如果您的项目未使用 Go 模块,请按以下方式设置:

go mod init <project>

然后重新运行下面的命令将 ent 添加到 go.mod 文件中:

go get entgo.io/ent/cmd/ent

在项目 <project>/ent 目录下添加 generate.go 文件:

package ent

//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema

最后在项目根目录下运行 go generate ./ent 来为项目模式的生成执行 ent 代码生成。

代码生成选项

运行 ent generate -h 查看代码生成选项:

generate go code for the schema directory

Usage:
ent generate [flags] path

Examples:
ent generate ./ent/schema
ent generate github.com/a8m/x

Flags:
--feature strings extend codegen with additional features
--header string override codegen header
-h, --help help for generate
--storage string storage driver to support in codegen (default "sql")
--target string target directory for codegen
--template strings external templates to execute

存储选项

ent 可以为 SQL 和 Gremlin 方言生成资源。默认方言是 SQL:

外部模板

ent 接受执行外部 Go模板。如果模板名称已经在 ent 中命名则将会被覆盖。否则执行输出将写入与模板同名的文件中。 标志格式支持 filedirglob

go run -mod=mod entgo.io/ent/cmd/ent generate --template <dir-path> --template glob="path/to/*.tmpl" ./ent/schema

参见 外部模板文档 了解更多信息。

entc作为包

另外一个运行 ent 代码生成的选项是使用下面的内容创建一个 ent/entc.go 文件并执行:

ent/entc.go
// +build ignore

package main

import (
"log"

"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
"entgo.io/ent/schema/field"
)

func main() {
if err := entc.Generate("./schema", &gen.Config{}); err != nil {
log.Fatal("running ent codegen:", err)
}
}
ent/generate.go
package ent

//go:generate go run -mod=mod entc.go

完整示例参见 GitHub

模式描述

运行下面的命令获取图模式的描述:

go run -mod=mod entgo.io/ent/cmd/ent describe ./ent/schema

示例输出如下:

Pet:
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
| Field | Type | Unique | Optional | Nillable | Default | UpdateDefault | Immutable | StructTag | Validators |
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
| id | int | false | false | false | false | false | false | json:"id,omitempty" | 0 |
| name | string | false | false | false | false | false | false | json:"name,omitempty" | 0 |
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
+-------+------+---------+---------+----------+--------+----------+
| Edge | Type | Inverse | BackRef | Relation | Unique | Optional |
+-------+------+---------+---------+----------+--------+----------+
| owner | User | true | pets | M2O | true | true |
+-------+------+---------+---------+----------+--------+----------+

User:
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
| Field | Type | Unique | Optional | Nillable | Default | UpdateDefault | Immutable | StructTag | Validators |
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
| id | int | false | false | false | false | false | false | json:"id,omitempty" | 0 |
| age | int | false | false | false | false | false | false | json:"age,omitempty" | 0 |
| name | string | false | false | false | false | false | false | json:"name,omitempty" | 0 |
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
+------+------+---------+---------+----------+--------+----------+
| Edge | Type | Inverse | BackRef | Relation | Unique | Optional |
+------+------+---------+---------+----------+--------+----------+
| pets | Pet | false | | O2M | false | true |
+------+------+---------+---------+----------+--------+----------+

代码生成钩子

entc 包提供了一项功能,可在代码生成阶段添加钩子(中间件)列表。 该功能特别适用于为模式添加自定义验证器,或通过图模式生成额外资源。

// +build ignore

package main

import (
"fmt"
"log"
"reflect"

"entgo.io/ent/entc"
"entgo.io/ent/entc/gen"
)

func main() {
err := entc.Generate("./schema", &gen.Config{
Hooks: []gen.Hook{
EnsureStructTag("json"),
},
})
if err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}

// EnsureStructTag ensures all fields in the graph have a specific tag name.
func EnsureStructTag(name string) gen.Hook {
return func(next gen.Generator) gen.Generator {
return gen.GenerateFunc(func(g *gen.Graph) error {
for _, node := range g.Nodes {
for _, field := range node.Fields {
tag := reflect.StructTag(field.StructTag)
if _, ok := tag.Lookup(name); !ok {
return fmt.Errorf("struct tag %q is missing for field %s.%s", name, node.Name, field.Name)
}
}
}
return next.Generate(g)
})
}
}

外部依赖

为在 ent 包下扩展生成的客户端和构建器,并将外部依赖项作为结构体字段注入,请在 ent/entc.go 文件中使用entc.Dependency 选项:

ent/entc.go
func main() {
opts := []entc.Option{
entc.Dependency(
entc.DependencyType(&http.Client{}),
),
entc.Dependency(
entc.DependencyName("Writer"),
entc.DependencyTypeInfo(&field.TypeInfo{
Ident: "io.Writer",
PkgPath: "io",
}),
),
}
if err := entc.Generate("./schema", &gen.Config{}, opts...); err != nil {
log.Fatalf("running ent codegen: %v", err)
}
}

然后在你的应用中使用它:

example_test.go
func Example_Deps() {
client, err := ent.Open(
"sqlite3",
"file:ent?mode=memory&cache=shared&_fk=1",
ent.Writer(os.Stdout),
ent.HTTPClient(http.DefaultClient),
)
if err != nil {
log.Fatalf("failed opening connection to sqlite: %v", err)
}
defer client.Close()
// An example for using the injected dependencies in the generated builders.
client.User.Use(func(next ent.Mutator) ent.Mutator {
return hook.UserFunc(func(ctx context.Context, m *ent.UserMutation) (ent.Value, error) {
_ = m.HTTPClient
_ = m.Writer
return next.Mutate(ctx, m)
})
})
// ...
}

完整示例参见 GitHub

特性标志

entc 包通过标志添加或移除代码生成中的一系列特性。

请参阅 特性标志页 了解更多信息。