メインコンテンツへスキップする

Eagerローディング

概要

ent は、(エッジを通じて) 関連するエンティティのクエリをサポートします。 関連するエンティティは、返されたオブジェクトの Edges フィールドに設定されます。

以下のスキーマで API がどのように見えるかの例を挙げてみましょう:

er-group-users

すべてのユーザーとそのペットを問い合わせる:

users, err := client.User.
Query().
WithPets().
All(ctx)
if err != nil {
return err
}
// 返されるユーザーは以下のようになります:
//
// [
// User {
// ID: 1,
// Name: "a8m",
// Edges: {
// Pets: [Pet(...), ...]
// ...
// }
// },
// ...
// ]
//
for _, u := range users {
for _, p := range u.Edges.Pets {
fmt.Printf("User(%v) -> Pet(%v)\n", u.ID, p.ID)
// Output:
// User(...) -> Pet(...)
}
}

Eagerローディングでは、複数の関連付け(ネストを含む) をクエリしたり、結果を フィルタ、並べ替え、または制限できます。 例:

admins, err := client.User.
Query().
Where(user.Admin(true)).
// `admins`に関連付けられた`pets`を追加します。
WithPets().
// `admins`に関連付けられた最初の5つの`groups`を追加します。
WithGroups(func(q *ent.GroupQuery) {
q.Limit(5) // 5つに限定
q.WithUsers() // それぞれの `groups`の`users`を追加します
}).
All(ctx)
if err != nil {
return err
}

// 返されるユーザーは以下のようになります
//
// [
// User {
// ID: 1,
// Name: "admin1",
// Edges: {
// Pets: [Pet(...), ...]
// Groups: [
// Group {
// ID: 7,
// Name: "GitHub",
// Edges: {
// Users: [User(...), ...]
// ...
// }
// }
// ]
// }
// },
// ...
// ]
//
for _, admin := range admins {
for _, p := range admin.Edges.Pets {
fmt.Printf("Admin(%v) -> Pet(%v)\n", u.ID, p.ID)
// Output:
// Admin(...) -> Pet(...)
}
for _, g := range admin.Edges.Groups {
for _, u := range g.Edges.Users {
fmt.Printf("Admin(%v) -> Group(%v) -> User(%v)\n", u.ID, g.ID, u.ID)
// Output:
// Admin(...) -> Group(...) -> User(...)
}
}
}

API

各query-builderは、それぞれのエッジに対して With<E>(...func(<N>Query)) 形式のメソッドのリストを持ちます。 <E>はエッジの名前(WithGroupsのような)、<N>はエッジのタイプ(GroupQueryのような)を表します。

この機能をサポートしているのは、SQL ダイアレクトだけです。

実装

クエリビルダーは複数の関連付けを読み込めるため、1 つの JOIN 操作を使用してそれらを読み込めません。 したがって、 ent は関連付けを読み込むための追加のクエリを実行します。 M2O/O2M および O2O のエッジに関する1つのクエリ、および M2M のエッジを読み込むための 2 つのクエリ。

なお、次のバージョンの ent では、これを改善することが期待されます。