边
概述
边是实体之间的关系(或者关联)。 例如,用户所拥有的(多只)宠物,或者用户组所关联的(多个)用户。
在上面的例子中,你可以看到使用边声明的2种关系。 让我们接着往下看。
1. pets
/ owner
边;用户的宠物和宠物的主人 -
ent/schema/user.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
)
// User schema.
type User struct {
ent.Schema
}
// Fields of the user.
func (User) Fields() []ent.Field {
return []ent.Field{
// ...
}
}
// Edges of the user.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("pets", Pet.Type),
}
}
ent/schema/pet.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
)
// Pet holds the schema definition for the Pet entity.
type Pet struct {
ent.Schema
}
// Fields of the Pet.
func (Pet) Fields() []ent.Field {
return []ent.Field{
// ...
}
}
// Edges of the Pet.
func (Pet) Edges() []ent.Edge {
return []ent.Edge{
edge.From("owner", User.Type).
Ref("pets").
Unique(),
}
}
你可以看到,一个 User
实体可以拥有 多个 宠物,但是一个 Pet
实体只能拥有 一名 主人。
在关系定义中,pets
边是一个 O2M (一对多)的关系,owner
边是一个 M2O (多对一)的关系。
User
实体拥有 pets/owner
的关系因为使用了 edge.To
, Pet
实体则仅有一个反向引用,是靠 edge.From
以及 Ref
方法实现。
Ref
方法明确了在 User
实体中我们所引用的那条边,因为存在从一个实体到其他实体多条引用的场景。
边/关系的数量可以使用 Unique
方法加以约束, 后续将作更多介绍。
2. users
/ groups
边; 用户组的用户和用户所属的用户组 -
ent/schema/group.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
)
// Group schema.
type Group struct {
ent.Schema
}
// Fields of the group.
func (Group) Fields() []ent.Field {
return []ent.Field{
// ...
}
}
// Edges of the group.
func (Group) Edges() []ent.Edge {
return []ent.Edge{
edge.To("users", User.Type),
}
}
ent/schema/user.go
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/edge"
)
// User schema.
type User struct {
ent.Schema
}
// Fields of the user.
func (User) Fields() []ent.Field {
return []ent.Field{
// ...
}
}
// Edges of the user.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.From("groups", Group.Type).
Ref("users"),
// "pets" declared in the example above.
edge.To("pets", Pet.Type),
}
}
如你所见,一个用户组能拥有多名用户,同时一名用户能属于多个用户组。
在定义关系时,users
的边是一个M2M (多对多)关系,同时groups
边同样也是一个M2M(多对多)关系。
To 和 From
edge.To
和 edge.From
是两个用于创建边/关系的生成器。
一个实体使用 edge.To
生成器定义一条边以构建关系模式,和使用 edge.From
生成器仅定义一个反向引用关系完全是两回事(命名不同)。
让我们通过一些例子来看看如何使用边定义不同的关系模式。
关系
- 一对一( O2O)两者之间
- 一对一(O2O)自引用
- 一对一(O2O)双向自引用
- 一对多(O2M )两者之间
- 一对多(O2M )自引用
- 多对多(M2M )两者之间
- 多对多(M2M )自引用
- 多对多(M2M)双向自引用
一对一( O2O)两者之间
在本例中,一名用户 仅有一张 信用卡,同时一张卡 只属一名 用户。
User
实体基于 edge.To
定义了名下的卡并将该引用关系命名 card
,同时 Card
实体基于 edge.From
定义了一个相对的反向引用并命名 owner
。
ent/schema/user.go
// Edges of the user.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("card", Card.Type).
Unique(),
}
}
ent/schema/card.go
// Edges of the Card.
func (Card) Edges() []ent.Edge {
return []ent.Edge{
edge.From("owner", User.Type).
Ref("card").
Unique().
// We add the "Required" method to the builder
// to make this edge required on entity creation.
// i.e. Card cannot be created without its owner.
Required(),
}
}
与这些边的交互API如下:
func Do(ctx context.Context, client *ent.Client) error {
a8m, err := client.User.
Create().
SetAge(30).
SetName("Mashraki").
Save(ctx)
if err != nil {
return fmt.Errorf("creating user: %w", err)
}
log.Println("user:", a8m)
card1, err := client.Card.
Create().
SetOwner(a8m).
SetNumber("1020").
SetExpired(time.Now().Add(time.Minute)).
Save(ctx)
if err != nil {
return fmt.Errorf("creating card: %w", err)
}
log.Println("card:", card1)
// Only returns the card of the user,
// and expects that there's only one.
card2, err := a8m.QueryCard().Only(ctx)
if err != nil {
return fmt.Errorf("querying card: %w", err)
}
log.Println("card:", card2)
// The Card entity is able to query its owner using
// its back-reference.
owner, err := card2.QueryOwner().Only(ctx)
if err != nil {
return fmt.Errorf("querying owner: %w", err)
}
log.Println("owner:", owner)
return nil
}
完整示例请参考 GitHub。
一对一(O2O)自引用
在这个链表的例子中(Linked-List),我们有一个 递归关系 名为 next
/prev
。 表中的每个结点 仅能拥有一个 next
结点。 如果结点A链到(使用 next
)结点B,B即可使用 prev
(反向关系引用)。
ent/schema/node.go
// Edges of the Node.
func (Node) Edges() []ent.Edge {
return []ent.Edge{
edge.To("next", Node.Type).
Unique().
From("prev").
Unique(),
}
}
如你所见,在自引用的关系中,你可以把边和它的引用在同一个构造器中声明。
func (Node) Edges() []ent.Edge {
return []ent.Edge{
+ edge.To("next", Node.Type).
+ Unique().
+ From("prev").
+ Unique(),
- edge.To("next", Node.Type).
- Unique(),
- edge.From("prev", Node.Type).
- Ref("next).
- Unique(),
}
}
与这些边交互的 API 如下:
func Do(ctx context.Context, client *ent.Client) error {
head, err := client.Node.
Create().
SetValue(1).
Save(ctx)
if err != nil {
return fmt.Errorf("creating the head: %w", err)
}
curr := head
// Generate the following linked-list: 1<->2<->3<->4<->5.
for i := 0; i < 4; i++ {
curr, err = client.Node.
Create().
SetValue(curr.Value + 1).
SetPrev(curr).
Save(ctx)
if err != nil {
return err
}
}
// Loop over the list and print it. `FirstX` panics if an error occur.
for curr = head; curr != nil; curr = curr.QueryNext().FirstX(ctx) {
fmt.Printf("%d ", curr.Value)
}
// Output: 1 2 3 4 5
// Make the linked-list circular:
// The tail of the list, has no "next".
tail, err := client.Node.
Query().
Where(node.Not(node.HasNext())).
Only(ctx)
if err != nil {
return fmt.Errorf("getting the tail of the list: %v", tail)
}
tail, err = tail.Update().SetNext(head).Save(ctx)
if err != nil {
return err
}
// Check that the change actually applied:
prev, err := head.QueryPrev().Only(ctx)
if err != nil {
return fmt.Errorf("getting head's prev: %w", err)
}
fmt.Printf("\n%v", prev.Value == tail.Value)
// Output: true
return nil
}
完整示例请参考 GitHub。
一对一(O2O)双向自引用
在这个用户配偶的例子中,我们定义了一个 对称的一对一(O2O)关系 名为 spouse
。 每名用户仅能有一名配偶。 如果A将其配偶设置成(使用 spouse
)B,B则可使用spouse
边查到其相应的配偶。
注意在双向自引用场景下没有所有者/反向引用关系。
ent/schema/user.go
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("spouse", User.Type).
Unique(),
}
}
与这些边的交互API如下:
func Do(ctx context.Context, client *ent.Client) error {
a8m, err := client.User.
Create().
SetAge(30).
SetName("a8m").
Save(ctx)
if err != nil {
return fmt.Errorf("creating user: %w", err)
}
nati, err := client.User.
Create().
SetAge(28).
SetName("nati").
SetSpouse(a8m).
Save(ctx)
if err != nil {
return fmt.Errorf("creating user: %w", err)
}
// Query the spouse edge.
// Unlike `Only`, `OnlyX` panics if an error occurs.
spouse := nati.QuerySpouse().OnlyX(ctx)
fmt.Println(spouse.Name)
// Output: a8m
spouse = a8m.QuerySpouse().OnlyX(ctx)
fmt.Println(spouse.Name)
// Output: nati
// Query how many users have a spouse.
// Unlike `Count`, `CountX` panics if an error occurs.
count := client.User.
Query().
Where(user.HasSpouse()).
CountX(ctx)
fmt.Println(count)
// Output: 2
// Get the user, that has a spouse with name="a8m".
spouse = client.User.
Query().
Where(user.HasSpouseWith(user.Name("a8m"))).
OnlyX(ctx)
fmt.Println(spouse.Name)
// Output: nati
return nil
}
注意,外键列可以配置并暴露为实体字段,如下使用边字段选项:
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("spouse_id").
Optional(),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("spouse", User.Type).
Unique().
Field("spouse_id"),
}
}
完整示例请参考 GitHub。
一对多(O2M )两者之间
在这个用户和宠物例子中,我们在用户与其宠物之间定义了一个一对多(O2M)的关系。 每个用户能够拥有多个宠物,一个宠物只能拥有一个主人。 如果用户 A 使用 pets
边添加了一个宠物 B,B 可以使用 owner
边(反向引用的边)获得它的主人。
注意:在 Pet
结构 (Schema) 的视角看,也是一个多对一(M2O)的关系。
ent/schema/user.go
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("pets", Pet.Type),
}
}
ent/schema/pet.go
// Edges of the Pet.
func (Pet) Edges() []ent.Edge {
return []ent.Edge{
edge.From("owner", User.Type).
Ref("pets").
Unique(),
}
}
与这些边的交互API如下:
func Do(ctx context.Context, client *ent.Client) error {
// Create the 2 pets.
pedro, err := client.Pet.
Create().
SetName("pedro").
Save(ctx)
if err != nil {
return fmt.Errorf("creating pet: %w", err)
}
lola, err := client.Pet.
Create().
SetName("lola").
Save(ctx)
if err != nil {
return fmt.Errorf("creating pet: %w", err)
}
// Create the user, and add its pets on the creation.
a8m, err := client.User.
Create().
SetAge(30).
SetName("a8m").
AddPets(pedro, lola).
Save(ctx)
if err != nil {
return fmt.Errorf("creating user: %w", err)
}
fmt.Println("User created:", a8m)
// Output: User(id=1, age=30, name=a8m)
// Query the owner. Unlike `Only`, `OnlyX` panics if an error occurs.
owner := pedro.QueryOwner().OnlyX(ctx)
fmt.Println(owner.Name)
// Output: a8m
// Traverse the sub-graph. Unlike `Count`, `CountX` panics if an error occurs.
count := pedro.
QueryOwner(). // a8m
QueryPets(). // pedro, lola
CountX(ctx) // count
fmt.Println(count)
// Output: 2
return nil
}
注意,外键列可以配置并暴露为实体字段,如下使用 Edge Field 选项:
// Fields of the Pet.
func (Pet) Fields() []ent.Field {
return []ent.Field{
field.Int("owner_id").
Optional(),
}
}
// Edges of the Pet.
func (Pet) Edges() []ent.Edge {
return []ent.Edge{
edge.From("owner", User.Type).
Ref("pets").
Unique().
Field("owner_id"),
}
}
完整示例请参考 GitHub。
一对多(O2M )自引用
在这个例子中,我们在树结点及其子结点(或它们的父结点)间定义了一个一对多(O2M)递归关系。
树中的每个结点 有多个 子结点,以及 一个 父结点。 如果结点A将B添加到其子结点, B即可使用 owner
边查到其所有者。
ent/schema/node.go
// Edges of the Node.
func (Node) Edges() []ent.Edge {
return []ent.Edge{
edge.To("children", Node.Type).
From("parent").
Unique(),
}
}
如你所见,在自引用的关系中,你可以把边和它的引用在同一个构造器中声明。
func (Node) Edges() []ent.Edge {
return []ent.Edge{
+ edge.To("children", Node.Type).
+ From("parent").
+ Unique(),
- edge.To("children", Node.Type),
- edge.From("parent", Node.Type).
- Ref("children").
- Unique(),
}
}
与这些边的交互API如下:
func Do(ctx context.Context, client *ent.Client) error {
root, err := client.Node.
Create().
SetValue(2).
Save(ctx)
if err != nil {
return fmt.Errorf("creating the root: %w", err)
}
// Add additional nodes to the tree:
//
// 2
// / \
// 1 4
// / \
// 3 5
//
// Unlike `Save`, `SaveX` panics if an error occurs.
n1 := client.Node.
Create().
SetValue(1).
SetParent(root).
SaveX(ctx)
n4 := client.Node.
Create().
SetValue(4).
SetParent(root).
SaveX(ctx)
n3 := client.Node.
Create().
SetValue(3).
SetParent(n4).
SaveX(ctx)
n5 := client.Node.
Create().
SetValue(5).
SetParent(n4).
SaveX(ctx)
fmt.Println("Tree leafs", []int{n1.Value, n3.Value, n5.Value})
// Output: Tree leafs [1 3 5]
// Get all leafs (nodes without children).
// Unlike `Int`, `IntX` panics if an error occurs.
ints := client.Node.
Query(). // All nodes.
Where(node.Not(node.HasChildren())). // Only leafs.
Order(ent.Asc(node.FieldValue)). // Order by their `value` field.
GroupBy(node.FieldValue). // Extract only the `value` field.
IntsX(ctx)
fmt.Println(ints)
// Output: [1 3 5]
// Get orphan nodes (nodes without parent).
// Unlike `Only`, `OnlyX` panics if an error occurs.
orphan := client.Node.
Query().
Where(node.Not(node.HasParent())).
OnlyX(ctx)
fmt.Println(orphan)
// Output: Node(id=1, value=2)
return nil
}
注意,外键列可以配置并暴露为实体字段,如下使用 Edge Field 选项:
// Fields of the Node.
func (Node) Fields() []ent.Field {
return []ent.Field{
field.Int("parent_id").
Optional(),
}
}
// Edges of the Node.
func (Node) Edges() []ent.Edge {
return []ent.Edge{
edge.To("children", Node.Type).
From("parent").
Unique().
Field("parent_id"),
}
}
完整示例请参考 GitHub。
多对多(M2M )两者之间
在这个用户组和用户例子中,我们在用户组与其用户之间定义了一个多对多(M2M)的关系。 每个用户组能够拥有多个用户,并且每个用户可以加入到多个用户组中。
ent/schema/group.go
// Edges of the Group.
func (Group) Edges() []ent.Edge {
return []ent.Edge{
edge.To("users", User.Type),
}
}
ent/schema/user.go
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.From("groups", Group.Type).
Ref("users"),
}
}
与这些边的交互API如下:
func Do(ctx context.Context, client *ent.Client) error {
// Unlike `Save`, `SaveX` panics if an error occurs.
hub := client.Group.
Create().
SetName("GitHub").
SaveX(ctx)
lab := client.Group.
Create().
SetName("GitLab").
SaveX(ctx)
a8m := client.User.
Create().
SetAge(30).
SetName("a8m").
AddGroups(hub, lab).
SaveX(ctx)
nati := client.User.
Create().
SetAge(28).
SetName("nati").
AddGroups(hub).
SaveX(ctx)
// Query the edges.
groups, err := a8m.
QueryGroups().
All(ctx)
if err != nil {
return fmt.Errorf("querying a8m groups: %w", err)
}
fmt.Println(groups)
// Output: [Group(id=1, name=GitHub) Group(id=2, name=GitLab)]
groups, err = nati.
QueryGroups().
All(ctx)
if err != nil {
return fmt.Errorf("querying nati groups: %w", err)
}
fmt.Println(groups)
// Output: [Group(id=1, name=GitHub)]
// Traverse the graph.
users, err := a8m.
QueryGroups(). // [hub, lab]
Where(group.Not(group.HasUsersWith(user.Name("nati")))). // [lab]
QueryUsers(). // [a8m]
QueryGroups(). // [hub, lab]
QueryUsers(). // [a8m, nati]
All(ctx)
if err != nil {
return fmt.Errorf("traversing the graph: %w", err)
}
fmt.Println(users)
// Output: [User(id=1, age=30, name=a8m) User(id=2, age=28, name=nati)]
return nil
}
完整示例请参考 GitHub。
多对多(M2M )自引用
在以下的 粉丝-被关注者 例子中,用户与他们的粉丝是 多对多(M2M) 关系。 每个用户可以关注 多名 用户,也可以有 多名 粉丝。
ent/schema/user.go
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("following", User.Type).
From("followers"),
}
}
如你所见,在自引用的关系中,你可以把边和它的引用在同一个构造器中声明。
func (User) Edges() []ent.Edge {
return []ent.Edge{
+ edge.To("following", User.Type).
+ From("followers"),
- edge.To("following", User.Type),
- edge.From("followers", User.Type).
- Ref("following"),
}
}
与这些边的交互API如下:
func Do(ctx context.Context, client *ent.Client) error {
// Unlike `Save`, `SaveX` panics if an error occurs.
a8m := client.User.
Create().
SetAge(30).
SetName("a8m").
SaveX(ctx)
nati := client.User.
Create().
SetAge(28).
SetName("nati").
AddFollowers(a8m).
SaveX(ctx)
// Query following/followers:
flw := a8m.QueryFollowing().AllX(ctx)
fmt.Println(flw)
// Output: [User(id=2, age=28, name=nati)]
flr := a8m.QueryFollowers().AllX(ctx)
fmt.Println(flr)
// Output: []
flw = nati.QueryFollowing().AllX(ctx)
fmt.Println(flw)
// Output: []
flr = nati.QueryFollowers().AllX(ctx)
fmt.Println(flr)
// Output: [User(id=1, age=30, name=a8m)]
// Traverse the graph:
ages := nati.
QueryFollowers(). // [a8m]
QueryFollowing(). // [nati]
GroupBy(user.FieldAge). // [28]
IntsX(ctx)
fmt.Println(ages)
// Output: [28]
names := client.User.
Query().
Where(user.Not(user.HasFollowers())).
GroupBy(user.FieldName).
StringsX(ctx)
fmt.Println(names)
// Output: [a8m]
return nil
}
完整示例请参考 GitHub。
多对多(M2M)双向自引用
在这个用户与朋友的例子中,我们定义了一个 对称的多对多(M2M)关系 名为 friends
。 每个用户可以 拥有多个 朋友。 如果用户 A 成为了 B 的朋友,那么 B 也是 A 的朋友。
注意在双向自引用场景下没有所有者/反向引用关系。
ent/schema/user.go
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("friends", User.Type),
}
}
与这些边的交互API如下:
func Do(ctx context.Context, client *ent.Client) error {
// Unlike `Save`, `SaveX` panics if an error occurs.
a8m := client.User.
Create().
SetAge(30).
SetName("a8m").
SaveX(ctx)
nati := client.User.
Create().
SetAge(28).
SetName("nati").
AddFriends(a8m).
SaveX(ctx)
// Query friends. Unlike `All`, `AllX` panics if an error occurs.
friends := nati.
QueryFriends().
AllX(ctx)
fmt.Println(friends)
// Output: [User(id=1, age=30, name=a8m)]
friends = a8m.
QueryFriends().
AllX(ctx)
fmt.Println(friends)
// Output: [User(id=2, age=28, name=nati)]
// Query the graph:
friends = client.User.
Query().
Where(user.HasFriends()).
AllX(ctx)
fmt.Println(friends)
// Output: [User(id=1, age=30, name=a8m) User(id=2, age=28, name=nati)]
return nil
}
完整示例请参考 GitHub。
边字段
边的 Field
选项,允许用户将外键暴露为结构 (Schema) 上的常规字段。 注意,只有持有外键 (边 id) 的关系才能使用这个选项。 Support for non-foreign-key fields in join tables is in progress (as of September 2021) and can be tracked with this GitHub Issue.
// Fields of the Post.
func (Post) Fields() []ent.Field {
return []ent.Field{
field.Int("author_id").
Optional(),
}
}
// Edges of the Post.
func (Post) Edges() []ent.Edge {
return []ent.Edge{
edge.To("author", User.Type).
// Bind the "author_id" field to this edge.
Field("author_id").
Unique(),
}
}
与边字段的交互API如下:
func Do(ctx context.Context, client *ent.Client) error {
p, err := c.Post.Query().
Where(post.AuthorID(id)).
OnlyX(ctx)
if err != nil {
log.Fatal(err)
}
fmt.Println(p.AuthorID) // Access the "author" foreign-key.
}
更多例子请参考 GitHub。
Migration To Edge Fields
As mentioned in the StorageKey section, Ent configures edge storage-keys (e.g. foreign-keys) by the edge.To
. Therefore, if you want to add a field to an existing edge (already exists in the database as a column), you need to set it up with the StorageKey
option as follows:
// Fields of the Post.
func (Post) Fields() []ent.Field {
return []ent.Field{
+ field.Int("author_id").
+ Optional(),
}
}
// Edges of the Post.
func (Post) Edges() []ent.Edge {
return []ent.Edge{
edge.From("author", User.Type).
+ Field("author_id").
+ StorageKey(edge.Column("post_author")).
Unique(),
}
}
Alternatively, this option can be configured on the edge-field instead:
// Fields of the Post.
func (Post) Fields() []ent.Field {
return []ent.Field{
+ field.Int("author_id").
+ StorageKey("post_author").
+ Optional(),
}
}
If you’re not sure how the foreign-key was named before using the edge-field option, check out the generated schema description in your project: <project>/ent/migrate/schema.go
.
Required
Edges can be defined as required in the entity creation using the Required
method on the builder.
// Edges of the Card.
func (Card) Edges() []ent.Edge {
return []ent.Edge{
edge.From("owner", User.Type).
Ref("card").
Unique().
Required(),
}
}
If the example above, a card entity cannot be created without its owner.
存储字段
By default, Ent configures edge storage-keys by the edge-owner (the schema that holds the edge.To
), and not the by back-reference (edge.From
). This is because back-references are optional and can be removed.
In order to use custom storage configuration for edges, use the StorageKey
method as follows:
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("pets", Pet.Type).
// Set the column name in the "pets" table for O2M relationship.
StorageKey(edge.Column("owner_id")),
edge.To("cars", Car.Type).
// Set the symbol of the foreign-key constraint for O2M relationship.
StorageKey(edge.Symbol("cars_owner_id")),
edge.To("friends", User.Type).
// Set the join-table, and the column names for a M2M relationship.
StorageKey(edge.Table("friends"), edge.Columns("user_id", "friend_id")),
edge.To("groups", Group.Type).
// Set the join-table, its column names and the symbols
// of the foreign-key constraints for M2M relationship.
StorageKey(
edge.Table("groups"),
edge.Columns("user_id", "group_id"),
edge.Symbols("groups_id1", "groups_id2")
),
}
}
结构体标记
可以使用 StructTag
方法将自定义结构体标记添加到生成的实体中。 注意:如果此选项未设置,或者未包含 json
标记,那么默认的 json
标记将会设置为字段名。
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("pets", Pet.Type).
// Override the default json tag "pets" with "owner" for O2M relationship.
StructTag(`json:"owner"`),
}
}
索引
Indexes can be defined on multi fields and some types of edges as well. However, you should note, that this is currently an SQL-only feature.
更多信息请参考 索引(Indexes ) 章节。
注解
Annotations
用于在生成代码时将任意的元数据附加到边对象。 模板扩展可以检索此元数据并直接使用。
注意元数据必须能序列化为JSON原始值(如struct,map或slice)。
// Pet schema.
type Pet struct {
ent.Schema
}
// Edges of the Pet.
func (Pet) Edges() []ent.Edge {
return []ent.Field{
edge.To("owner", User.Type).
Ref("pets").
Unique().
Annotations(entgql.Annotation{
OrderField: "OWNER",
}),
}
}
在模板章节了解更多关于注解及其使用的相关信息。
命名规范
根据惯例字段的命名应使用snake_case
(蛇形命名法)。 由ent
生成相应的结构体字段使用是Go规范的PascalCase
(帕斯卡命名法)。 在需要PascalCase
时,您可以借助StorageKey
或StructTag
方法实现。