快速開始
簡介
ent 是一個簡單而強大的Go語言實體框架,它使得構建和維護大型數據模型的應用程序變得容易,同時ent遵循以下原則:
- 輕鬆地將數據庫模式建模為圖形結構
- 將模式定義為可編程的Go語言代碼
- 基於代碼生成的靜態類型
- 易於編寫的數據庫查詢和圖遍歷
- 簡單地擴展和使用Go模版進行自定義
設置Go環境
如果你的項目目錄在GOPATH之外,或者你不熟悉GOPATH,可通過如下的命令進行Go module設置
go mod init entdemo
創建第一個模式(Schema)
在項目的根目錄運行以下命令:
go run -mod=mod entgo.io/ent/cmd/ent new <Schema-name>
該命令會在指定目錄:<project>/ent/schema/下生成指定<Schema-name>的模式(示例中Schema為User):
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
}
向Schema中添加2個字段:
package schema
import (
"entgo.io/ent"
"entgo.io/ent/schema/field"
)
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.Int("age").
Positive(),
field.String("nickname").
Default("unknown"),
}
}
在項目的根目錄運行go generate命令生成文件:
go generate ./ent
生成文件如下:
ent
├── client.go
├── config.go
├── context.go
├── ent.go
├── generate.go
├── mutation.go
... truncated
├── schema
│ └── user.go
├── tx.go
├── user
│ ├── user.go
│ └── where.go
├── user.go
├── user_create.go
├── user_delete.go
├── user_query.go
└── user_update.go
創建第一個實體(Entity)
首先,創建一個新的ent.Client,示例中將使用MySQL
package main
import (
"context"
"log"
"entdemo/ent"
_ "github.com/go-sql-driver/mysql"
)
func main() {
client, err := ent.Open("mysql", "<user>:<pass>@tcp(<host>:<port>)/<database>?parseTime=True")
if err != nil {
log.Fatalf("failed opening connection to mysql: %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)
}
}
然後我們,準備創建user,示例中通過調用CreateerUser函數進行創建:
func CreateUser(ctx context.Context, client *ent.Client) (*ent.User, error) {
u, err := client.User.Create().
SetAge(18).
SetNickname("tester").
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating user: %w", err)
}
log.Println("user was created: ", u)
return u, nil
}
查詢實體
ent為每一個實體模式生成了一個包含斷言、默認值、校驗器以及存儲元素(列名、主鍵等)的額外信息的包
package main
import (
"log"
"entdemo/ent"
"entdemo/ent/user"
)
func QueryUser(ctx context.Context, client *ent.CLient) (*ent.User, error) {
u, err := client.User.Query().
Where(user.Nickname).
// `Only` fails if no user found,
// or more than 1 user returned.
Only(ctx)
if err != nil {
return nil, fmt.Errorf("failed quering user: %w", err)
}
log.Println("user returned: ", u)
return u, nil
}
添加第一個條邊(關係)
在教程的這個部分,我們在該模式中想要聲明一條到另一個實體的邊
首先創建2個額外的實體:Car和Group
同樣地,通過ent cli進行模式的初始化:
go run -mod=mod entgo.io/ent/cmd/ent new Car Group
然後手動增加一些字段:
//Fieids of the Car.
func (Car) Fields() []ent.Field {
return []ent.Field{
field.String("model"),
field.Time("registered_at"),
}
}
// Fields of the Group.
func (Group) Fields() []ent.Field {
return []ent.Field{
field.String("name").
Match(regexp.MustCompile("[a-zA-Z_]+$")),
}
}
讓我們來定義第一個關係,從User到Car的邊意味着user可擁有一或多個car,但car只能屬於一個user(一對多的關係)
添加“cars”邊到User模式中,然後運行go generate ./ent命令:
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.To("cars", Car.Type),
}
}
在示例中繼續創建2個car然後添加到user中:
import (
"entdemo/ent"
"entdemo/ent/car"
"entdemo/ent/user"
)
func CreateCars(ctx context.Context, client *ent.Client) (*ent.User, error) {
// Create a new car with model "Tesla".
tesla, err := client.Car.Create().
SetModel("Tesla").
SetRegisteredAt(time.Now()).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating car: %w", err)
}
log.Println("car was created: ", tesla)
// Create a new car with model "Ford".
ford, err := client.Car.Create().
SetModel("Ford").
SetRegisteredAt(time.Now()).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating car: %w", err)
}
// Create a new user, and add it the 2 cars.
tester, err := client.User.Create().
SetAge(18).
SetNickname("tester").
AddCars(tesla, ford).
Save(ctx)
if err != nil {
return nil, fmt.Errorf("failed creating user: %w", err)
}
log.Println("user was created: ", tester)
return tester, nil
}
查詢cars邊(關係):
import (
"log"
"entdemo/ent"
"entdemo/ent/car"
)
func QueryCars(ctx context.Context, tester *ent.Client) error {
cars, err := tester.QueryCars().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 := tester.QueryCars().
Where(car.Model("Ford")).
Only(ctx)
if err != nil {
return fmt.Errorf("failed querying user cars: %w", err)
}
log.Println(ford)
return nil
}