跳到主要内容

预加载

概览

ent 支持查询关联的实体 (通过其边)。 关联的实体会填充到返回对象的 Edges 字段中。

让我们通过以下例子,了解与 Schema 相关的 API:

er-group-users

查询所有用户及其宠物:

users, err := client.User.
Query().
WithPets().
All(ctx)
if err != nil {
return err
}
// The returned users look as follows:
//
// [
// 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(...)
}
}

预加载允许同时查询多个关联 (包括嵌套),也可以对其结果进行筛选、排序或限制数量。 例如:

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

每个查询构造器,都会为每一条边生成形如 With<E>(...func(<N>Query)) 的方法。 <E> 是边的名称 (如, WithGroups),<N> 是边的类型 (如, GroupQuery).

请注意,只有 SQL后端 支持此功能。

实现

由于查询构造器可以加载多个关联,无法使用一个 JOIN 操作加载它们。 因此,ent 加载关联时会进行额外的查询。 M2O/O2MO2O 的边会进行一次查询, M2M 的边会进行2次查询。

关于此,我们预计在下一个版本的 ent 中改进。