• ent 基本使用 三 边(关系处理)


    ent 提供了图查询的能力,实际上在关系数据库中的表现就是relation,以下代码接前文

    添加边(关系)

    • 添加schema
    entc init Car Group

    效果:

    • 添加字段
      car
    package schema
    import (
     "github.com/facebookincubator/ent"
     "github.com/facebookincubator/ent/schema/field"
    )
    // Car holds the schema definition for the Car entity.
    type Car struct {
     ent.Schema
    }
    // Fields of the Car.
    func (Car) Fields() []ent.Field {
     return []ent.Field{
      field.String("model"),
      field.Time("registered_at"),
     }
    }
    // Edges of the Car.
    func (Car) Edges() []ent.Edge {
     return nil
    }
     

    Group

    package schema
    import (
     "regexp"
     "github.com/facebookincubator/ent"
     "github.com/facebookincubator/ent/schema/field"
    )
    // Group holds the schema definition for the Group entity.
    type Group struct {
     ent.Schema
    }
    // Fields of the Group.
    func (Group) Fields() []ent.Field {
     return []ent.Field{
      field.String("name").
       // regexp validation for group name.
       Match(regexp.MustCompile("[a-zA-Z_]+$")),
     }
    }
    // Edges of the Group.
    func (Group) Edges() []ent.Edge {
     return nil
    }
     
     
    • 定义关系
      以下是一个用户拥有多辆汽车,但是车只能拥有一个所有者


    边定义(user schema)

     
    package schema
    import (
     "github.com/facebookincubator/ent"
     "github.com/facebookincubator/ent/schema/edge"
     "github.com/facebookincubator/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("cars", Car.Type),
     }
    }
     
     
    • 生成代码
    entc generate ./ent/schema
     

    效果

    • 创建car 处理

      注意需要运行scheme 迁移 go run cmd/migration/main.go

    package main
    import (
     "context"
     "fmt"
     "log"
     "time"
     _ "github.com/go-sql-driver/mysql"
     "github.com/rongfengliang/ent-demo/ent"
    )
    func main() {
     client, err := ent.Open("mysql", "root:dalongrong@tcp(127.0.0.1)/gogs")
     if err != nil {
      log.Fatalf("failed opening connection to sqlite: %v", err)
     }
     defer client.Close()
     ctx := context.Background()
     u, err := createCars(ctx, client)
     if err != nil {
      log.Fatal("some wrong", err)
     } else {
      log.Printf("user %s", u)
     }
    }
    func createCars(ctx context.Context, client *ent.Client) (*ent.User, error) {
     // creating 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: %v", err)
     }
     // creating 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: %v", err)
     }
     log.Println("car was created: ", ford)
     // create a new user, and add it the 2 cars.
     a8m, err := client.User.
      Create().
      SetAge(30).
      SetName("a8m").
      AddCars(tesla, ford).
      Save(ctx)
     if err != nil {
      return nil, fmt.Errorf("failed creating user: %v", err)
     }
     log.Println("user was created: ", a8m)
     return a8m, nil
    }
     
     

    运行效果

    go run cmd/edge/car/main.go 
    2019/10/14 14:26:06 car was created: Car(id=2, model=Ford, registered_at=2019-10-14 14:26:06.869078 +0800 CST m=+0.007888096)
    2019/10/14 14:26:06 user was created: User(id=6, age=30, name=a8m)
    2019/10/14 14:26:06 user User(id=6, age=30, name=a8m)
    • 生成的ddl
      car
    CREATE TABLE `cars` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `model` varchar(255) COLLATE utf8mb4_bin NOT NULL,
      `registered_at` timestamp NULL DEFAULT NULL,
      `user_car_id` bigint(20) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `cars_users_cars` (`user_car_id`),
      CONSTRAINT `cars_users_cars` FOREIGN KEY (`user_car_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
     
     

    ER 模型

    • 查询car
     
    func QueryCars(ctx context.Context, a8m *ent.User) error {
        cars, err := a8m.QueryCars().All(ctx)
        if err != nil {
            return fmt.Errorf("failed querying user cars: %v", err)
        }
        log.Println("returned cars:", cars)
        // what about filtering specific cars.
        ford, err := a8m.QueryCars().
            Where(car.ModelEQ("Ford")).
            Only(ctx)
        if err != nil {
            return fmt.Errorf("failed querying user cars: %v", err)
        }
        log.Println(ford)
        return nil
    }

    添加BackRef

    实际上就是上边说的约束,一辆车只能有一个拥有着

    • 给car 对象添加边的约束
     
    package schema
    import (
        "github.com/facebookincubator/ent"
        "github.com/facebookincubator/ent/schema/edge"
        "github.com/facebookincubator/ent/schema/field"
    )
    // Car holds the schema definition for the Car entity.
    type Car struct {
        ent.Schema
    }
    // Fields of the Car.
    func (Car) Fields() []ent.Field {
        return []ent.Field{
            field.String("model"),
            field.Time("registered_at"),
        }
    }
    // Edges of the Car.
    func (Car) Edges() []ent.Edge {
        return []ent.Edge{
            // create an inverse-edge called "owner" of type `User`
            // and reference it to the "cars" edge (in User schema)
            // explicitly using the `Ref` method.
            edge.From("owner", User.Type).
                Ref("cars").
                // setting the edge to unique, ensure
                // that a car can have only one owner.
                Unique(),
        }
    }
    • 生成代码
    entc generate ./ent/schema
    • 运行schema 迁移
    go run cmd/migration/main.go

    效果
    ddl

     
    CREATE TABLE `cars` (
      `id` bigint(20) NOT NULL AUTO_INCREMENT,
      `model` varchar(255) COLLATE utf8mb4_bin NOT NULL,
      `registered_at` timestamp NULL DEFAULT NULL,
      `user_car_id` bigint(20) DEFAULT NULL,
      `owner_id` bigint(20) DEFAULT NULL,
      PRIMARY KEY (`id`),
      KEY `cars_users_cars` (`user_car_id`),
      CONSTRAINT `cars_users_cars` FOREIGN KEY (`user_car_id`) REFERENCES `users` (`id`) ON DELETE SET NULL
    ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_bin
     

    • 查询
      cmd/edge/car/main.go
     
    package main
    import (
        "context"
        "fmt"
        "log"
        "time"
        _ "github.com/go-sql-driver/mysql"
        "github.com/rongfengliang/ent-demo/ent"
    )
    func main() {
        client, err := ent.Open("mysql", "root:dalongrong@tcp(127.0.0.1)/gogs")
        if err != nil {
            log.Fatalf("failed opening connection to sqlite: %v", err)
        }
        defer client.Close()
        ctx := context.Background()
        u, err := createCars(ctx, client)
        if err != nil {
            log.Fatal("some wrong", err)
        } else {
            log.Printf("user %s", u)
        }
        QueryCarUsers(ctx, u)
    }
    func createCars(ctx context.Context, client *ent.Client) (*ent.User, error) {
        // creating 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: %v", err)
        }
        // creating 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: %v", err)
        }
        log.Println("car was created: ", ford)
        // create a new user, and add it the 2 cars.
        a8m, err := client.User.
            Create().
            SetAge(30).
            SetName("a8m").
            AddCars(tesla, ford).
            Save(ctx)
        if err != nil {
            return nil, fmt.Errorf("failed creating user: %v", err)
        }
        log.Println("user was created: ", a8m)
        return a8m, nil
    }
    func QueryCarUsers(ctx context.Context, a8m *ent.User) error {
        cars, err := a8m.QueryCars().All(ctx)
        if err != nil {
            return fmt.Errorf("failed querying user cars: %v", err)
        }
        // query the inverse edge.
        for _, ca := range cars {
            owner, err := ca.QueryOwner().Only(ctx)
            if err != nil {
                return fmt.Errorf("failed querying car %q owner: %v", ca.Model, err)
            }
            log.Printf("car %q owner: %q
    ", ca.Model, owner.Name)
        }
        return nil
    }
     
     

    效果

    go run cmd/edge/car/main.go 
    2019/10/14 14:54:08 car was created: Car(id=4, model=Ford, registered_at=2019-10-14 14:54:08.647003 +0800 CST m=+0.007479891)
    2019/10/14 14:54:08 user was created: User(id=7, age=30, name=a8m)
    2019/10/14 14:54:08 user User(id=7, age=30, name=a8m)
    2019/10/14 14:54:08 car "Tesla" owner: "a8m"
    2019/10/14 14:54:08 car "Ford" owner: "a8m"
     
     

    创建m2m 的关系

    需要实现的关系图如下:

    • 添加边的处理
      groups
     
    package schema
    import (
     "regexp"
     "github.com/facebookincubator/ent"
     "github.com/facebookincubator/ent/schema/edge"
     "github.com/facebookincubator/ent/schema/field"
    )
    // Group holds the schema definition for the Group entity.
    type Group struct {
     ent.Schema
    }
    // Fields of the Group.
    func (Group) Fields() []ent.Field {
     return []ent.Field{
      field.String("name").
       // regexp validation for group name.
       Match(regexp.MustCompile("[a-zA-Z_]+$")),
     }
    }
    // Edges of the Group.
    func (Group) Edges() []ent.Edge {
     return []ent.Edge{
      edge.To("users", User.Type),
     }
    }
     
     

    users

    package schema
    import (
     "github.com/facebookincubator/ent"
     "github.com/facebookincubator/ent/schema/edge"
     "github.com/facebookincubator/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("cars", Car.Type),
      edge.From("groups", Group.Type).
       Ref("users"),
     }
    }
    • 生成代码
    entc generate ./ent/schema
    • 运行模式迁移
    go run cmd/migration/main.go
     

    生成的er 模型,从图中我们可以看出是通过中间表解决m2m的问题,通过ent/migrate/schema.go 代码可以也看出来

    说明

    以上是一个简单的关系处理的学习,后边会看看图查询的处理

    参考资料

    https://entgo.io/docs/getting-started/
    https://github.com/rongfengliang/ent-demo

  • 相关阅读:
    javascript判断页面第一次加载还是刷新操作【转】
    vs 2008 不能切换到设计视图的解决办法
    sql update 触发器 获得被update的行的信息
    方便winform中的数据验证,制作一个使用正则表达式验证数据的复合控件
    求一个n选x的算法
    在html链接里执行js和使用标签事件执行的不同
    咸吃萝卜淡操心:导入xlsx文件表格新增数据
    我亲爱的你,有两副面孔:表格末尾添加新内容
    Torture:跨域访问的功臣:window.name
    那么轻,那么重:图片下载与压缩包下载
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/11673455.html
Copyright © 2020-2023  润新知