入门指南
安装
项目自带一个名为 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 目录下创建 2 个模型文件(user.go 和 pet.go)。
如果 ent 目录不存在,它也会自动创建。约定是在项目根目录下建立 ent 目录。
生成资源文件
添加若干字段和边后,您需要生成用于操作实体的资源文件。
从项目根目录运行 ent generate,或使用 go generate:
go generate ./ent
generate 命令会为模型生成以下资源文件:
- 用于操作数据图的
Client和Tx对象 - 每个模型类型的 CRUD 构建器。详见 CRUD
- 每个模型类型的实体对象(Go 结构体)
- 包含用于与构建器交互的常量和谓词的包
- 用于 SQL 方言的
migrate包。详见 迁移 - 用于添加变更中间件的
hook包。详见 钩子
entc 与 ent 的版本兼容性
在项目中使用 ent CLI 时,需要确保 CLI 使用的版本与项目使用的 ent 版本完全一致。
实现此目标的方法之一是让 go generate 在运行 ent 时使用 go.mod 文件中指定的版本。
如果项目未使用 Go modules,请按以下方式创建:
go mod init <项目名>
然后重新运行以下命令,将 ent 添加到 go.mod 文件中:
go get entgo.io/ent/cmd/ent
在项目中添加 generate.go 文件,位置为 <项目名>/ent:
package ent
//go:generate go run -mod=mod entgo.io/ent/cmd/ent generate ./schema
最后,您可以从项目根目录运行 go generate ./ent,以便对项目模型运行 ent 代码生成。
代码生成选项
要了解更多代码生成选项信息,请运行 ent generate -h:
生成模式目录的 Go 代码
用法:
ent generate [标志] 路径
示例:
ent generate ./ent/schema
ent generate github.com/a8m/x
标志:
--feature strings 使用附加功能扩展代码生成
--header string 覆盖代码生成头部信息
-h, --help 帮助信息
--storage string 代码生成支持的存储驱动(默认为 "sql")
--target string 代码生成目标目录
--template strings 要执行的外部模板
存储选项
ent 可以为 SQL 和 Gremlin 方言生成资源文件。默认方言为 SQL。
外部模板
ent 支持执行外部 Go 模板。如果模板名称已在 ent 中定义,则会覆盖现有模板。
否则,会将执行输出写入与模板同名的文件中。标志格式支持 file、dir 和 glob,如下所示:
go run -mod=mod entgo.io/ent/cmd/ent generate --template <目录路径> --template glob="路径/*.tmpl" ./ent/schema
更多信息和示例请参阅外部模板文档。
将 entc 作为包使用
另一种运行 ent 代码生成的方法是创建一个名为 ent/entc.go 的文件,内容如下,
然后通过 ent/generate.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)
}
}
package ent
//go:generate go run -mod=mod entc.go
完整示例可在 GitHub 查看。
模型描述
要获取图模型的描述信息,请运行:
go run -mod=mod entgo.io/ent/cmd/ent describe ./ent/schema
输出示例如下:
Pet:
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
| 字段 | 类型 | 唯一 | 可选 | 可空 | 默认值 | 更新默认值 | 不可变 | 结构标签 | 验证器 |
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
| id | int | false | false | false | false | false | false | json:"id,omitempty" | 0 |
| name | string | false | false | false | false | false | false | json:"name,omitempty" | 0 |
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
+-------+------+---------+---------+----------+--------+----------+
| 边 | 类型 | 反向 | 反向引用 | 关系 | 唯一 | 可选 |
+-------+------+---------+---------+----------+--------+----------+
| owner | User | true | pets | M2O | true | true |
+-------+------+---------+---------+----------+--------+----------+
User:
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
| 字段 | 类型 | 唯一 | 可选 | 可空 | 默认值 | 更新默认值 | 不可变 | 结构标签 | 验证器 |
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
| 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 |
+-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
+------+------+---------+---------+----------+--------+----------+
| 边 | 类型 | 反向 | 反向引用 | 关系 | 唯一 | 可选 |
+------+------+---------+---------+----------+--------+----------+
| 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 确保图中的所有字段都有特定的标签名。
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("字段 %s.%s 缺少结构标签 %q", node.Name, field.Name, name)
}
}
}
return next.Generate(g)
})
}
}
外部依赖项
为了扩展 ent 包下生成的客户端和构建器,并向其中注入外部依赖项作为结构体字段,
请在您的 ent/entc.go 文件中使用 entc.Dependency 选项:
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)
}
}
然后在应用程序中使用:
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()
// 在生成的构建器中使用注入依赖项的示例。
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 包提供了一系列代码生成功能,可以使用标志来添加或移除。
更多信息请参阅功能标志页面。