miyazi888の覚え書き日記

学習したことを書き留めてます。

entを試してみた その2(関連テーブル追加とJOIN)

前回のブログでentの基本的なCRUDの使い方がなんとなくわかったので今回は関連テーブルがある場合についてを検証したブログとなる。

前回 https://miyazi888.hatenablog.com/entry/2023/05/05/114518

関連テーブルを追加

ent new Comment

スキーマ変更

この段階で指定するEdgesというのがどうやらテーブルのリレーションを定義する部分っぽい。

ent/shcema/comment.go

package schema

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

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

// Fields of the Comment.
func (Comment) Fields() []ent.Field {
    return []ent.Field{
        field.Int("user_id"),
        field.String("comment").Default("unknown"),
    }
}

// Edges of the Comment.
func (Comment) Edges() []ent.Edge {
    return []ent.Edge{
        edge.From("user", User.Type).
            Ref("comments").
            Unique().
            Required().
            Field("user_id"),
    }
}

ent/schema/user.go

package schema

import (
    "entgo.io/ent"
    "entgo.io/ent/dialect/entsql"
    "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.String("name").Default("unknown"),
        field.Int("age").Positive(),
        field.String("nickname").Default("unknown"),
    }
}

// Edges of the User.
func (User) Edges() []ent.Edge {
    return []ent.Edge{
        edge.To("comments", Comment.Type).
            Annotations(entsql.Annotation{
                OnDelete: entsql.Cascade,
            }),
    }
}

上記スキーマを元にentityを生成

go generate ./ent

DBに反映する為にmigrate

go run migrate/migrate.go

動作検証

main.go

func cleanUp() {
    client := db.NewDBClient()
    ctx := context.Background()

    _, err := client.Debug().User.Delete().Exec(ctx)
    if err != nil {
        fmt.Printf("failed deleting user: %v", err)
        return
    }

    db.CloseDB(client)
}

func addUserAndComment() {
    client := db.NewDBClient()
    ctx := context.Background()

    // 1件追加
    usr, err := client.Debug().User.
        Create().
        SetName("user2").
        SetAge(30).
        Save(ctx)
    if err != nil {
        fmt.Printf("failed creating user: %v", err)
        return
    }

    // コメント1件追加
    _, err = client.Debug().Comment.
        Create().
        SetUserID(usr.ID).
        SetComment("comment1").
        Save(ctx)
    if err != nil {
        fmt.Printf("failed creating comment: %v", err)
        return
    }

    // コメント1件追加
    _, err = client.Debug().Comment.
        Create().
        SetUserID(usr.ID).
        SetComment("comment2").
        Save(ctx)
    if err != nil {
        fmt.Printf("failed creating comment: %v", err)
        return
    }

    // user2のコメントを全件取得
    comments, err := usr.QueryComments().All(ctx)
    if err != nil {
        fmt.Printf("failed getting comments: %v", err)
        return
    }

    for _, comment := range comments {
        fmt.Println(comment.Comment) // comment1, comment2
    }

    // 'comment2'を持つユーザー一覧を取得
    usrs, err := client.Debug().User.Query().Where(func(s *sql.Selector) {
        t := sql.Table(comment.Table)
        s.Join(t).On(s.C(user.FieldID), t.C(comment.FieldUserID))
        s.Where(sql.EQ(t.C(comment.FieldComment), "comment2"))
    }).All(ctx)
    if err != nil {
        fmt.Printf("failed getting users: %v", err)
        return
    }

    for _, usr := range usrs {
        fmt.Println(usr.Name) // user2
    }

    db.CloseDB(client)
}

func main() {
    cleanUp()

    // crud()

    addUserAndComment()
}

これを実行するとusersテーブルにuser2が追加され、commentsテーブルにコメントが2件追加される。

go run main.go

参考

Edges | ent

述語 | ent