预加载

概览

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

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

er-group-users

查询所有用户及其宠物:

  1. users, err := client.User.
  2. Query().
  3. WithPets().
  4. All(ctx)
  5. if err != nil {
  6. return err
  7. }
  8. // The returned users look as follows:
  9. //
  10. // [
  11. // User {
  12. // ID: 1,
  13. // Name: "a8m",
  14. // Edges: {
  15. // Pets: [Pet(...), ...]
  16. // ...
  17. // }
  18. // },
  19. // ...
  20. // ]
  21. //
  22. for _, u := range users {
  23. for _, p := range u.Edges.Pets {
  24. fmt.Printf("User(%v) -> Pet(%v)\n", u.ID, p.ID)
  25. // Output:
  26. // User(...) -> Pet(...)
  27. }
  28. }

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

  1. admins, err := client.User.
  2. Query().
  3. Where(user.Admin(true)).
  4. // 填充与 `admins` 相关联的 `pets`
  5. WithPets().
  6. // 填充与 `admins` 相关联的前5个 `groups`
  7. WithGroups(func(q *ent.GroupQuery) {
  8. q.Limit(5) // 限量5个
  9. q.WithUsers() // 为 `groups` 填充它们的 `users`.
  10. }).
  11. All(ctx)
  12. if err != nil {
  13. return err
  14. }
  15. // 返回的结果类似于:
  16. //
  17. // [
  18. // User {
  19. // ID: 1,
  20. // Name: "admin1",
  21. // Edges: {
  22. // Pets: [Pet(...), ...]
  23. // Groups: [
  24. // Group {
  25. // ID: 7,
  26. // Name: "GitHub",
  27. // Edges: {
  28. // Users: [User(...), ...]
  29. // ...
  30. // }
  31. // }
  32. // ]
  33. // }
  34. // },
  35. // ...
  36. // ]
  37. //
  38. for _, admin := range admins {
  39. for _, p := range admin.Edges.Pets {
  40. fmt.Printf("Admin(%v) -> Pet(%v)\n", u.ID, p.ID)
  41. // Output:
  42. // Admin(...) -> Pet(...)
  43. }
  44. for _, g := range admin.Edges.Groups {
  45. for _, u := range g.Edges.Users {
  46. fmt.Printf("Admin(%v) -> Group(%v) -> User(%v)\n", u.ID, g.ID, u.ID)
  47. // Output:
  48. // Admin(...) -> Group(...) -> User(...)
  49. }
  50. }
  51. }

API

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

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

实现

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

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