引言

安装

本项目有一个叫做 ent 的代码工具。 若要安装 ent 运行以下命令:

  1. go get -d entgo.io/ent/cmd/ent

初始化一个新的 Schema

为了生成一个或多个 schema 模板,运行 ent init 如下:

  1. go run entgo.io/ent/cmd/ent init User Pet

init 将在 ent/schema 目录下创建 2个 schemas (user.gopet.go)。 如果 ent 目录不存在,将自动创建。 一般约定将 ent 目录放在项目的根目录下。

生成资源文件

每次添加或修改 fieldsedges后, 你都需要生成新的实体. 在项目的根目录执行 ent generate或直接执行go generate命令重新生成资源文件:

  1. go generate ./ent

generate将会按照schema模板生成生成以下资源:

  • ClientTx 对象用于与图的交互。
  • 每个schema对应的增删改查, 查看 CRUD 了解更多信息。
  • 每个schema的实体对象(Go结构体)。
  • 含常量和查询条件的包,用于与生成器交互。
  • 用于数据迁移的migrate包。 查看 迁移 获取更多信息。
  • 一个在变更前执行的 hook 包 查看 钩子 获取更多信息。

entcent之间的版本兼容性

在项目中使用 ent CLI时,需要确保CLI使用的版本与项目使用的 ent 版本相同。

保证此的一个方法是通过 go generate 来使用 go.mod 内所定义的 ent CLI版本。 如果您的项目没有使用 Go modules, 请设置一个:

  1. go mod init <project>

然后执行以下命令,以便将 ent 添加到您的 go.mod 文件:

  1. go get -d entgo.io/ent/cmd/ent

generate.go 文件添加到你项目的<project>/ent 目录中:

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

最后,你可以执行 go generate ./ent ,以便在您的项目方案中执行 ent 代码生成。

代码生成选项

关于代码生成选项的更多信息,执行 ent generate -h

  1. generate go code for the schema directory
  2. Usage:
  3. ent generate [flags] path
  4. Examples:
  5. ent generate ./ent/schema
  6. ent generate github.com/a8m/x
  7. Flags:
  8. --feature strings extend codegen with additional features
  9. --header string override codegen header
  10. -h, --help help for generate
  11. --idtype [int string] type of the id field (default int)
  12. --storage string storage driver to support in codegen (default "sql")
  13. --target string target directory for codegen
  14. --template strings external templates to execute

Storage选项

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

外部模板

ent 接受执行外部 Go 模板文件。 如果模板名称已由 ent定义,它将覆盖现有的模板。 否则,它将把执行后的输出写入到 与模板相同名称的文件。 支持参数 file, dirglob 如下所示:

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

更多信息和示例可在 外部模板 中找到。

Use entc as a Package

Another option for running ent code generation is to create a file named ent/entc.go with the following content, and then the ent/generate.go file to execute it:

ent/entc.go

  1. // +build ignore
  2. package main
  3. import (
  4. "log"
  5. "entgo.io/ent/entc"
  6. "entgo.io/ent/entc/gen"
  7. "entgo.io/ent/schema/field"
  8. )
  9. func main() {
  10. if err := entc.Generate("./schema", &gen.Config{}); err != nil {
  11. log.Fatal("running ent codegen:", err)
  12. }
  13. }

ent/generate.go

  1. package ent
  2. //go:generate go run -mod=mod entc.go

完整示例请参阅 GitHub.

Schema描述

要获取您Schema的描述,请执行:

  1. go run entgo.io/ent/cmd/ent describe ./ent/schema

示例如下:

  1. Pet:
  2. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  3. | Field | Type | Unique | Optional | Nillable | Default | UpdateDefault | Immutable | StructTag | Validators |
  4. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  5. | id | int | false | false | false | false | false | false | json:"id,omitempty" | 0 |
  6. | name | string | false | false | false | false | false | false | json:"name,omitempty" | 0 |
  7. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  8. +-------+------+---------+---------+----------+--------+----------+
  9. | Edge | Type | Inverse | BackRef | Relation | Unique | Optional |
  10. +-------+------+---------+---------+----------+--------+----------+
  11. | owner | User | true | pets | M2O | true | true |
  12. +-------+------+---------+---------+----------+--------+----------+
  13. User:
  14. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  15. | Field | Type | Unique | Optional | Nillable | Default | UpdateDefault | Immutable | StructTag | Validators |
  16. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  17. | id | int | false | false | false | false | false | false | json:"id,omitempty" | 0 |
  18. | age | int | false | false | false | false | false | false | json:"age,omitempty" | 0 |
  19. | name | string | false | false | false | false | false | false | json:"name,omitempty" | 0 |
  20. +-------+---------+--------+----------+----------+---------+---------------+-----------+-----------------------+------------+
  21. +------+------+---------+---------+----------+--------+----------+
  22. | Edge | Type | Inverse | BackRef | Relation | Unique | Optional |
  23. +------+------+---------+---------+----------+--------+----------+
  24. | pets | Pet | false | | O2M | false | true |
  25. +------+------+---------+---------+----------+--------+----------+

代码生成Hooks (钩子)

entc 软件包提供了一个将钩子(中间件) 添加到代码生成阶段的方法。 这个方法适合在你需要对graph schema进行自定义验证或者生成附加资源时使用.

  1. // +build ignore
  2. package main
  3. import (
  4. "fmt"
  5. "log"
  6. "reflect"
  7. "entgo.io/ent/entc"
  8. "entgo.io/ent/entc/gen"
  9. )
  10. func main() {
  11. err := entc.Generate("./schema", &gen.Config{
  12. Hooks: []gen.Hook{
  13. EnsureStructTag("json"),
  14. },
  15. })
  16. if err != nil {
  17. log.Fatalf("running ent codegen: %v", err)
  18. }
  19. }
  20. // EnsureStructTag ensures all fields in the graph have a specific tag name.
  21. func EnsureStructTag(name string) gen.Hook {
  22. return func(next gen.Generator) gen.Generator {
  23. return gen.GenerateFunc(func(g *gen.Graph) error {
  24. for _, node := range g.Nodes {
  25. for _, field := range node.Fields {
  26. tag := reflect.StructTag(field.StructTag)
  27. if _, ok := tag.Lookup(name); !ok {
  28. return fmt.Errorf("struct tag %q is missing for field %s.%s", name, node.Name, field.Name)
  29. }
  30. }
  31. }
  32. return next.Generate(g)
  33. })
  34. }
  35. }

External Dependencies

In order to extend the generated client and builders under the ent package, and inject them external dependencies as struct fields, use the entc.Dependency option in your ent/entc.go file:

ent/entc.go

  1. func main() {
  2. opts := []entc.Option{
  3. entc.Dependency(
  4. entc.DependencyType(&http.Client{}),
  5. ),
  6. entc.Dependency(
  7. entc.DependencyName("Writer"),
  8. entc.DependencyTypeInfo(&field.TypeInfo{
  9. Ident: "io.Writer",
  10. PkgPath: "io",
  11. }),
  12. ),
  13. }
  14. if err := entc.Generate("./schema", &gen.Config{}, opts...); err != nil {
  15. log.Fatalf("running ent codegen: %v", err)
  16. }
  17. }

Then, use it in your application:

example_test.go

  1. func Example_Deps() {
  2. client, err := ent.Open(
  3. "sqlite3",
  4. "file:ent?mode=memory&cache=shared&_fk=1",
  5. ent.Writer(os.Stdout),
  6. ent.HTTPClient(http.DefaultClient),
  7. )
  8. if err != nil {
  9. log.Fatalf("failed opening connection to sqlite: %v", err)
  10. }
  11. defer client.Close()
  12. // An example for using the injected dependencies in the generated builders.
  13. client.User.Use(func(next ent.Mutator) ent.Mutator {
  14. return hook.UserFunc(func(ctx context.Context, m *ent.UserMutation) (ent.Value, error) {
  15. _ = m.HTTPClient
  16. _ = m.Writer
  17. return next.Mutate(ctx, m)
  18. })
  19. })
  20. // ...
  21. }

The full example exists in GitHub.

Feature Flags

The entc package provides a collection of code-generation features that be added or removed using flags.

For more information, please see the features-flags page.