id: schema-fields

title: Fields

简介

模式中的字段相当于顶点的属性。 例如,User 有 4 个字段: age, name, usernamecreated_at.

re-fields-properties

模式的 Fields 方法可以返回字段列表。例如:

  1. package schema
  2. import (
  3. "time"
  4. "github.com/facebookincubator/ent"
  5. "github.com/facebookincubator/ent/schema/field"
  6. )
  7. // User schema.
  8. type User struct {
  9. ent.Schema
  10. }
  11. // Fields of the user.
  12. func (User) Fields() []ent.Field {
  13. return []ent.Field{
  14. field.Int("age"),
  15. field.String("name"),
  16. field.String("username").
  17. Unique(),
  18. field.Time("created_at").
  19. Default(time.Now),
  20. }
  21. }

默认情况下,所有字段都是必填的,但是可以使用 Optional 方法将其设置为可选的。

类型

ent 目前支持以下类型:

  • go 的全部数值类型。如: int, uint8, float64 等等.
  • bool
  • string
  • time.Time
  • []byte (只支持 SQL).
  • JSON (只支持 SQL) - 实验性.
  • Enum (只支持 SQL).


  1. package schema
  2. import (
  3. "time"
  4. "net/url"
  5. "github.com/facebookincubator/ent"
  6. "github.com/facebookincubator/ent/schema/field"
  7. )
  8. // User schema.
  9. type User struct {
  10. ent.Schema
  11. }
  12. // Fields of the user.
  13. func (User) Fields() []ent.Field {
  14. return []ent.Field{
  15. field.Int("age").
  16. Positive(),
  17. field.Float("rank").
  18. Optional(),
  19. field.Bool("active").
  20. Default(false),
  21. field.String("name").
  22. Unique(),
  23. field.Time("created_at").
  24. Default(time.Now),
  25. field.JSON("url", &url.URL{}).
  26. Optional(),
  27. field.JSON("strings", []string{}).
  28. Optional(),
  29. field.Enum("state").
  30. Values("on", "off").
  31. Optional(),
  32. }
  33. }

要了解有关每种类型如何映射到其数据库类型的更多细节,请转到 Migration 部分。

默认值

非唯一 字段支持通过 .Default.UpdateDefault 方法设置默认值.

  1. // Fields of the User.
  2. func (User) Fields() []ent.Field {
  3. return []ent.Field{
  4. field.Time("created_at").
  5. Default(time.Now),
  6. field.Time("updated_at").
  7. Default(time.Now).
  8. UpdateDefault(time.Now),
  9. }
  10. }

验证器

字段验证器是类型为 func(T) error 的函数,其使用模式中的 Validate 方法定义,并应用在创建或更新实体之前。

字段验证器支持 string 和所有数值类型。

  1. package schema
  2. import (
  3. "errors"
  4. "regexp"
  5. "strings"
  6. "time"
  7. "github.com/facebookincubator/ent"
  8. "github.com/facebookincubator/ent/schema/field"
  9. )
  10. // Group schema.
  11. type Group struct {
  12. ent.Schema
  13. }
  14. // Fields of the group.
  15. func (Group) Fields() []ent.Field {
  16. return []ent.Field{
  17. field.String("name").
  18. Match(regexp.MustCompile("[a-zA-Z_]+$")).
  19. Validate(func(s string) error {
  20. if strings.ToLower(s) == s {
  21. return errors.New("group name must begin with uppercase")
  22. }
  23. return nil
  24. }),
  25. }
  26. }

内建验证器

ent 为支持的每种类型提供了一些内建验证器

  • 数值类型:

    • Positive()
    • Negative()
    • Min(i) - 验证字段值是否大于 i.
    • Max(i) - 验证字段值是否小于 i.
    • Range(i, j) - 验证字段值是否在 [i, j] 区间。
  • string

    • MinLen(i)
    • MaxLen(i)
    • Match(regexp.Regexp)

可选字段

可选字段是实体创建时是非必填的字段,在数据库中将其设置为可空字段。 不同于边,字段默认是必填的,但是可以使用 Optional 方法将其设为可选字段。

  1. // Fields of the user.
  2. func (User) Fields() []ent.Field {
  3. return []ent.Field{
  4. field.String("required_name"),
  5. field.String("optional_name").
  6. Optional(),
  7. }
  8. }

区分零值

Nillable, 有时候你想区分字段的零值和 nil;例如,你想数据库中某个字段的值,既能为 0 又能为 NULL。那么 Nillable 就是为此而生的。

如果你有一个可选(Optional)的类型 T ,将其设为 Nillable 会在生成的结构体中得到一个 *T. 因此,如果数据库中的该字段返回 NULL,这个类型值为 nil. 否则,他将包含一个指向实际数据的指针。

例如,有如下模式:

  1. // Fields of the user.
  2. func (User) Fields() []ent.Field {
  3. return []ent.Field{
  4. field.String("required_name"),
  5. field.String("optional_name").
  6. Optional(),
  7. field.String("nillable_name").
  8. Optional().
  9. Nillable(),
  10. }
  11. }

User 生成的结构体如下:

  1. // ent/user.go
  2. package ent
  3. // User entity.
  4. type User struct {
  5. RequiredName string `json:"required_name,omitempty"`
  6. OptionalName string `json:"optional_name,omitempty"`
  7. NillableName *string `json:"nillable_name,omitempty"`
  8. }

不可变字段

Immutable, 不可变字段是指其值只能在创建实体时赋值的字段。即,不会为该字段生成更新方法。

  1. // Fields of the user.
  2. func (User) Fields() []ent.Field {
  3. return []ent.Field{
  4. field.String("name"),
  5. field.Time("created_at").
  6. Default(time.Now),
  7. Immutable(),
  8. }
  9. }

唯一性

可以通过 Unique 方法将字段定义为唯一的(唯一索引)。需要注意的是唯一字段不能有默认值。

  1. // Fields of the user.
  2. func (User) Fields() []ent.Field {
  3. return []ent.Field{
  4. field.String("name"),
  5. field.String("nickname").
  6. Unique(),
  7. }
  8. }

存储键

可以通过 StorageKey 方法自定义存储名。 在 SQL 中,会将字段名映射为列名;在 Gremlin 中,会将字段名映射为属性名。

  1. // Fields of the user.
  2. func (User) Fields() []ent.Field {
  3. return []ent.Field{
  4. field.String("name").
  5. StorageKey(`old_name"`),
  6. }
  7. }

索引

可以在多个字段或者某些边上添加索引。但是,需要注意的是,目前只有 SQL 支持索引特性。

更多关于索引的内容,可以查阅 索引 部分。

标签

可以使用 StructTag 方法为生成的实体添加标签。 注意,如果没有提供或者提供的标签不包含 json, 那么 entc 在生成代码时,会添加默认的 json 标签。

  1. // Fields of the user.
  2. func (User) Fields() []ent.Field {
  3. return []ent.Field{
  4. field.String("name").
  5. StructTag(`gqlgen:"gql_name"`),
  6. }
  7. }

其它结构体字段

默认情况下,entc 会根据 schema.Fields 方法中配置的字段生成实体模型。 例如,给定如下模式配置:

  1. // User schema.
  2. type User struct {
  3. ent.Schema
  4. }
  5. // Fields of the user.
  6. func (User) Fields() []ent.Field {
  7. return []ent.Field{
  8. field.Int("age").
  9. Optional().
  10. Nillable(),
  11. field.String("name").
  12. StructTag(`gqlgen:"gql_name"`),
  13. }
  14. }

生成的实体如下:

  1. // User is the model entity for the User schema.
  2. type User struct {
  3. // Age holds the value of the "age" field.
  4. Age *int `json:"age,omitempty"`
  5. // Name holds the value of the "name" field.
  6. Name string `json:"name,omitempty" gqlgen:"gql_name"`
  7. }

为了将 不存储在数据库中的字段 生成到实体中,请使用 外部模板. 例如:

  1. {{ define "model/fields/additional" }}
  2. {{- if eq $.Name "User" }}
  3. // StaticField defined by template.
  4. StaticField string `json:"static,omitempty"`
  5. {{- end }}
  6. {{ end }}

生成的实体如下:

  1. // User is the model entity for the User schema.
  2. type User struct {
  3. // Age holds the value of the "age" field.
  4. Age *int `json:"age,omitempty"`
  5. // Name holds the value of the "name" field.
  6. Name string `json:"name,omitempty" gqlgen:"gql_name"`
  7. // StaticField defined by template.
  8. StaticField string `json:"static,omitempty"`
  9. }

脱敏

可以使用 Sensitive 方法将 String 字段设置为敏感字段。敏感字段不会被打印,在编码时也会被忽略。

注意:敏感字段不能有 struct 标签(StructTag 方法)。

  1. // User schema.
  2. type User struct {
  3. ent.Schema
  4. }
  5. // Fields of the user.
  6. func (User) Fields() []ent.Field {
  7. return []ent.Field{
  8. field.String("password").
  9. Sensitive(),
  10. }
  11. }