zoukankan      html  css  js  c++  java
  • 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

  • 相关阅读:
    sublime text 4 vim 插件配置
    ssh-keygen 的使用
    distribution transaction solution
    bilibili 大数据 视频下载 you-get
    Deepin 20.2.1 安装 MS SQL 2019 容器版本
    【转】使用Linux下Docker部署MSSQL并加载主机目录下的数据库
    【转】You Can Now Use OneDrive in Linux Natively Thanks to Insync
    dotnet 诊断工具安装命令
    Linux 使用 xrandr 设置屏幕分辨率
    【转】CentOS 7.9 2009 ISO 官方原版镜像下载
  • 原文地址:https://www.cnblogs.com/rongfengliang/p/11673455.html
Copyright © 2011-2022 走看看