初始化

go mod init <project>
go install entgo.io/ent/cmd/ent@latest
go run entgo.io/ent/cmd/ent init User Class

执行初始化后的目录结构:

--schema
----user.go
----class.go
--generate.go

得到schema定义框架。如下:

// schema/user.go
package schema

import "entgo.io/ent"

// User holds the schema definition for the User entity.
type User struct {
    ent.Schema
}

// Fields of the User.
func (User) Fields() []ent.Field {
    return nil
}

// Edges of the User.
func (User) Edges() []ent.Edge {
    return nil
}
// generate.go
package ent

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

补充实体和边

// schema/user.go
package schema

import (
	"entgo.io/ent"
	"entgo.io/ent/schema/edge"
	"entgo.io/ent/schema/field"
)

// User holds the schema definition for the User entity.
type User struct {
	ent.Schema
}

// Fields of the User.
func (User) Fields() []ent.Field {
	return []ent.Field{
		field.Int("age").
			Positive(),
		field.String("name").
			Default("unknown"),
	}
}

// Edges of the User.
func (User) Edges() []ent.Edge {
	return []ent.Edge{
		edge.To("classes", Class.Type),
	}
}

生成代码

go generate ./ent
或者
go generate ./...

创建实体和边数据


package main

import (
	"context"
	"fmt"
	_ "github.com/mattn/go-sqlite3"
	"log"
	"test/ent"
	"test/ent/class"
	"test/ent/user"
)

func main() {
	client, err := ent.Open("sqlite3", "file:./ent.db?cache=shared&_fk=1")
	if err != nil {
		log.Fatalf("failed opening connection to sqlite: %v", err)
	}
	defer client.Close()
	// Run the auto migration tool.
	if err := client.Schema.Create(context.Background()); err != nil {
		log.Fatalf("failed creating schema resources: %v", err)
	}

	//_, err = CreateUser(context.Background(), client)
	//if err != nil {
	//	log.Fatalf("failed creating schema resources: %v", err)
	//}
	//u, err := QueryUser(context.Background(), client)
	//if err != nil {
	//	log.Fatalf("failed creating schema resources: %v", err)
	//}
	//_ = QueryClasses(context.Background(), u)
    //创建俩个class,然后创建一个用户关联这俩个class
	_, err = CreateClasses(context.Background(), client)
	if err != nil {
		log.Fatalf("failed creating schema resources: %v", err)
	} 
}

func CreateUser(ctx context.Context, client *ent.Client) (*ent.User, error) {
	u, err := client.User.
		Create().
		SetAge(22).
		SetName("868").
		Save(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed creating user: %w", err)
	}
	log.Println("user was created: ", u)
	return u, nil
}

func QueryUser(ctx context.Context, client *ent.Client) (*ent.User, error) {
	u, err := client.User.
		Query().
		Where(user.Name("121")).
		// `Only` 在 找不到用户 或 找到多于一个用户 时报错,
		Only(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed querying user: %w", err)
	}
	log.Println("user returned: ", u)
	return u, nil
}

func CreateClasses(ctx context.Context, client *ent.Client) (*ent.User, error) {
	math, err := client.Class.
		Create().
		SetClassName("math").
		SetScore(100).
		Save(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed creating class: %w", err)
	}
	log.Println("class was created: ", math)

	chinese, err := client.Class.
		Create().
		SetClassName("chinese").
		SetScore(100).
		Save(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed creating car: %w", err)
	}
	log.Println("car was created: ", chinese)

	// 新建一个用户,将两辆车添加到他的名下
	a8m, err := client.User.
		Create().
		SetAge(18).
		SetName("121").
		AddClasses(math, chinese).
		Save(ctx)
	if err != nil {
		return nil, fmt.Errorf("failed creating user: %w", err)
	}
	log.Println("user was created: ", a8m)
	return a8m, nil
}

func QueryClasses(ctx context.Context, a8m *ent.User) error {
	cars, err := a8m.QueryClasses().All(ctx)
	if err != nil {
		return fmt.Errorf("failed querying user cars: %w", err)
	}
	log.Println("returned cars:", cars)

	// What about filtering specific cars.
	ford, err := a8m.QueryClasses().
		Where(class.ClassName("math")).
		Only(ctx)
	if err != nil {
		return fmt.Errorf("failed querying user cars: %w", err)
	}
	log.Println(ford)
	return nil
}

实体和关系在Golang数据结构中的体现

// User is the model entity for the User schema.
type User struct {
	config `json:"-"`
	// ID of the ent.
	ID int `json:"id,omitempty"`
	// Age holds the value of the "age" field.
	Age int `json:"age,omitempty"`
	// Name holds the value of the "name" field.
	Name string `json:"name,omitempty"`
	// Edges holds the relations/edges for other nodes in the graph.
	// The values are being populated by the UserQuery when eager-loading is set.
	Edges UserEdges `json:"edges"`
}
// UserEdges holds the relations/edges for other nodes in the graph.
type UserEdges struct {
	// Classes holds the value of the classes edge.
	Classes []*Class `json:"classes,omitempty"`
	// loadedTypes holds the information for reporting if a
	// type was loaded (or requested) in eager-loading or not.
	loadedTypes [1]bool
}
// Class is the model entity for the Class schema.
type Class struct {
	config `json:"-"`
	// ID of the ent.
	ID int `json:"id,omitempty"`
	// ClassName holds the value of the "class_name" field.
	ClassName string `json:"class_name,omitempty"`
	// Score holds the value of the "score" field.
	Score        int64 `json:"score,omitempty"`
	user_classes *int
}

实体和边在关系型数据库表中的体现

表:users

idagename
130a8m
222868
518121

表:classes

idclass_namescoreuser_classes
7math1005
8chinese1005

TODO:关于其他形式的边的存储结构待补充

参考资料