👏
[ent][Go]M2M Edgesで自動生成されるjoin table にindex追加する
TL;DR
- GoのORM, entでM2MのEdgesを定義した場合、自動的にjoin用の中間テーブル(join tableと呼ばれている)が生成される
- M2M Edgeds : https://entgo.io/docs/schema-edges/#m2m-two-types
- 自動生成されるテーブルはschemaファイルが存在しないため、通常のようにindexesを定義できない
- 現状はmigration hooksでschema定義を修正する必要があるとのこと。将来的にはoptionで指定できるようになるらしい(2021/8現在)
- migration hooks : https://entgo.io/docs/migrate#migration-hooks
Example
※PostgreSQLを想定
- 下記のようなUser, Group schemaを定義する
- これによりUserとGroupを関連付ける
group_users
というテーブルが自動生成される
- これによりUserとGroupを関連付ける
type User struct {
ent.Schema
}
// Fields of the User.
func (User) Fields() []ent.Field {
return []ent.Field{
field.String("user_name"),
}
}
// Edges of the User.
func (User) Edges() []ent.Edge {
return []ent.Edge{
edge.From("groups", Group.Type).Ref("users"),
}
}
type Group struct {
ent.Schema
}
// Fields of the Group.
func (Group) Fields() []ent.Field {
return []ent.Field{
field.String("group_name"),
}
}
// Edges of the Group.
func (Group) Edges() []ent.Edge {
return []ent.Edge{
edge.To("users", User.Type),
}
}
-
group_users
DDL
-- public.group_users definition
CREATE TABLE public.group_users (
group_id int8 NOT NULL,
user_id int8 NOT NULL,
CONSTRAINT group_users_pkey PRIMARY KEY (group_id, user_id)
);
-- public.group_users foreign keys
ALTER TABLE public.group_users ADD CONSTRAINT group_users_group_id FOREIGN KEY (group_id) REFERENCES public."groups"(id) ON DELETE CASCADE;
ALTER TABLE public.group_users ADD CONSTRAINT group_users_user_id FOREIGN KEY (user_id) REFERENCES public.users(id) ON DELETE CASCADE;
- そして下記のようなcodeを実行するとする
client.User.Query().
Where(user.IDEQ(u.ID)).
WithGroups().
All(ctx)
- その時に実行されるSQLは下記になる
driver.Query: query=SELECT "user_id", "group_id" FROM "group_users" WHERE "user_id" IN ($1) args=[1]
-
group_users_pkey PRIMARY KEY (group_id, user_id)
しかないためindexが存在しない
driver.Query: query=SELECT DISTINCT "users"."id", "users"."user_name" FROM "users" WHERE "users"."id" = $1 args=[1]
driver.Query: query=SELECT "user_id", "group_id" FROM "group_users" WHERE "user_id" IN ($1) args=[1]
driver.Query: query=SELECT DISTINCT "groups"."id", "groups"."group_name" FROM "groups" WHERE "groups"."id" IN ($1) args=[1]
-
group_users
は自動生成されshemaファイルが存在しないため、通常のようにindexesを定義できない - 現状はmigration hooksでschema定義を修正する必要があるとのこと。将来的にはoptionで指定できるようになるとのこと(2021/8現在)
- 下記でindexを追加できることを確認
- 他にいい方法あったら教えて下さいmm
db.Schema.Create(context.Background(),
schema.WithHooks(func(next schema.Creator) schema.Creator {
return schema.CreateFunc(func(ctx context.Context, tables ...*schema.Table) error {
// [NOTE]
// Add index to group_users schema.
for _, t := range tables {
if t.Name == "group_users" {
t.Indexes = append(t.Indexes, &schema.Index{
Name: "group_users_user_id",
Unique: false,
Columns: []*schema.Column{t.Columns[1]}, // user_id
})
}
}
return next.Create(ctx, tables...)
})
}),
)
Discussion