使用标准 SQL JOIN
我假设您使用的是 jOOQ 的 code generator。编写联接就像在 SQL 中编写联接一样:
ctx.select() // Optionally, list columns here, explicitly
.from(USERS)
.join(USER_KEYS).on(USERS.ID.eq(USER_KEYS.USER_ID))
.join(KEYS).on(USER_KEYS.KEY_ID.eq(KEYS.ID))
.where(USERS.NAME.eq("something"))
.fetch();
嵌套集合
如果存在额外的表(例如 UserRoles)等怎么办?一般来说,如何获取一个用户和所有关联的行,通过外键表关联?
我不确定这是否仍然是同一个问题。上面可能是关于如何进行一般的连接,这一篇似乎更具体的是关于如何获取嵌套集合?
因为JOIN 总是会产生笛卡尔积,这是不可取的,一旦您加入了多对多路径。从 jOOQ 3.14 开始,如果您的数据库支持,您可以使用 SQL/XML 或 SQL/JSON 作为解决方法。从 jOOQ 3.15 开始,您可以使用MULTISET。例如,JSON 解决方案可能如下所示:
List<User> users =
ctx.select(jsonObject(
jsonEntry("id", USERS.ID),
jsonEntry("name", USERS.NAME),
jsonEntry("keys", field(
select(jsonArrayAgg(jsonObject(KEYS.NAME, KEYS.ID)))
.from(KEYS)
.join(USER_KEYS).on(KEYS.ID.eq(USER_KEYS.KEY_ID))
.where(USER_KEYS.USER_ID.eq(USER.ID))
)),
jsonEntry("roles", field(
select(jsonArrayAgg(jsonObject(ROLES.NAME, ROLES.ID)))
.from(ROLES)
.join(USER_ROLES).on(ROLES.ID.eq(USER_ROLES.ROLE_ID))
.where(USER_ROLES.USER_ID.eq(USER.ID))
))
))
.from(USERS)
.where(USERS.NAME.eq("something"))
.fetchInto(User.class);
假设 User 类看起来像这样,并且您的类路径中有 Gson 或 Jackson 以从 JSON 映射到 Java 数据结构:
class Key {
long id;
String name;
}
class Role {
long id;
String name;
}
class User {
long id;
String name;
List<Key> keys;
List<Role> roles;
}
当然,您不必映射到 Java 数据结构并直接生成 JSON 结果,无需进一步映射。 See also this blog post for more details,或this one explaining how to use MULTISET。
请注意,JSON_ARRAYAGG() 将空集聚合到 NULL,而不是空集 []。 If that's a problem, use COALESCE()
MULTISET 解决方案如下所示:
List<User> users =
ctx.select(
USERS.ID,
USERS.NAME,
multiset(
select(KEYS.NAME, KEYS.ID)
.from(KEYS)
.join(USER_KEYS).on(KEYS.ID.eq(USER_KEYS.KEY_ID))
.where(USER_KEYS.USER_ID.eq(USER.ID))
).as("keys").convertFrom(r -> r.map(Records.mapping(Key::new))),
multiset(
select(ROLES.NAME, ROLES.ID)
.from(ROLES)
.join(USER_ROLES).on(ROLES.ID.eq(USER_ROLES.ROLE_ID))
.where(USER_ROLES.USER_ID.eq(USER.ID))
).as("roles").convertFrom(r -> r.map(Records.mapping(Role::new)))
)
.from(USERS)
.where(USERS.NAME.eq("something"))
.fetch(Records.mapping(User::new));
上述使用各种Records.mapping() 重载和ad-hoc data type conversion 的方法假定存在不可变的构造函数,例如,如果您的类是Java 16 记录,您会得到:
record Key (int id, String name) {}
record Role (int id, String name) {}
record User (int id, String name, List<Key> keys, List<Role> roles) {}
使用多个查询
如果您不能使用上述方法,因为您还不能使用 jOOQ 3.14,或者因为您的 RDBMS 不支持 SQL/XML 或 SQL/JSON,您可以运行多个查询并手动组合结果最后。