JOOQ 获取外键 table
JOOQ fetch over foreign keys table
我有三个table:
Users
Keys
UserKeys
UserKeys
table 具有来自 Users
和 Keys
table 的主键以建立用户和键之间的关系。
如何获取 User
及其所有相关键?
如果存在额外的 tables(例如 UserRoles
)等等。一般来说,如何获取用户和所有关联的行,通过外键关联 tables ?
使用标准 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();
嵌套集合
What if additional tables exist (for instance UserRoles), etc. In general, how to fetch a user and all associated rows, related via foreign keys tables?
我不确定这是否仍然是同一个问题。上面可能是关于如何进行一般的连接,这个似乎更具体地讲了如何获取嵌套集合?
因为一旦加入多个 to-many 路径,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
class 看起来像这样,并且您的 class 路径上有 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, or this one explaining how to use MULTISET
.
请注意,JSON_ARRAYAGG()
将空集聚合为 NULL
,而不是空集 []
。
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()
overloads along with ad-hoc data type conversion 的方法假定存在不可变的构造函数,例如如果您的 classes 是 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,您可以 运行 几个查询和 assemble 手动结果。
我有三个table:
Users
Keys
UserKeys
UserKeys
table 具有来自 Users
和 Keys
table 的主键以建立用户和键之间的关系。
如何获取 User
及其所有相关键?
如果存在额外的 tables(例如 UserRoles
)等等。一般来说,如何获取用户和所有关联的行,通过外键关联 tables ?
使用标准 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();
嵌套集合
What if additional tables exist (for instance UserRoles), etc. In general, how to fetch a user and all associated rows, related via foreign keys tables?
我不确定这是否仍然是同一个问题。上面可能是关于如何进行一般的连接,这个似乎更具体地讲了如何获取嵌套集合?
因为一旦加入多个 to-many 路径,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
class 看起来像这样,并且您的 class 路径上有 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, or this one explaining how to use MULTISET
.
请注意,JSON_ARRAYAGG()
将空集聚合为 NULL
,而不是空集 []
。
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()
overloads along with ad-hoc data type conversion 的方法假定存在不可变的构造函数,例如如果您的 classes 是 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,您可以 运行 几个查询和 assemble 手动结果。