将 jOOQ 与 JPA EntityResult 结合使用
适用于 ✅ 开源版 ✅ 专业版 ✅ 企业版
这些章节的目标是描述如何在您有充分理由的情况下这样做。然而,大多数情况下,最好直接使用 jOOQ 执行查询,特别是如果您想使用 jOOQ 更高级的功能。这篇博文说明了直接使用 jOOQ 执行查询的各种原因。
虽然 JPA 指定了如何实现映射(例如,使用 jakarta.persistence.SqlResultSetMapping
),但对于您如何生成 SQL 语句没有任何限制。以下简单示例展示了如何从 jOOQ 生成的 SQL 语句中生成 JPABook
和 JPAAuthor
实体(来自上一节)。
为此,我们需要指定 SqlResultSetMapping
。这可以在任何实体上完成,在本例中,我们使用 jakarta.persistence.EntityResult
@SqlResultSetMapping( name = "bookmapping", entities = { @EntityResult( entityClass = JPABook.class, fields = { @FieldResult(name = "id", column = "b_id"), @FieldResult(name = "title", column = "b_title"), @FieldResult(name = "author", column = "b_author_id") } ), @EntityResult( entityClass = JPAAuthor.class, fields = { @FieldResult(name = "id", column = "a_id"), @FieldResult(name = "firstName", column = "a_first_name"), @FieldResult(name = "lastName", column = "a_last_name") } ) } )
请注意,我们需要在以下之间进行映射
-
FieldResult.name()
,它对应于实体的属性名称 -
FieldResult.column()
,它对应于 SQL 结果的列名
有了上面的样板代码,我们现在可以使用 jOOQ 和 JPA 获取实体
public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, String resultSetMapping) { // Extract the SQL statement from the jOOQ query: Query result = em.createNativeQuery(query.getSQL(), resultSetMapping); // Extract the bind values from the jOOQ query: List<Object> values = query.getBindValues(); for (int i = 0; i < values.size(); i++) { result.setParameter(i + 1, values.get(i)); } return result.getResultList(); }
public static <E> List<E> nativeQuery(EntityManager em, org.jooq.Query query, String resultSetMapping) { // Extract the SQL statement from the jOOQ query: Query result = em.createNativeQuery(query.getSQL(), resultSetMapping); // Extract the bind values from the jOOQ query: int i = 1; for (Param<?> param : query.getParams().values()) if (!param.isInline()) result.setParameter(i++, convertToDatabaseType(param)); return result.getResultList(); } static <T> Object convertToDatabaseType(Param<T> param) { return param.getBinding().converter().to(param.getValue()); }
使用上述 API
现在我们已经完成了所有设置,我们可以使用上面的 API 运行 jOOQ 查询来获取 JPA 实体,如下所示
List<Object[]> result = nativeQuery(em, DSL.using(configuration .select( AUTHOR.ID.as("a_id"), AUTHOR.FIRST_NAME.as("a_first_name"), AUTHOR.LAST_NAME.as("a_last_name"), BOOK.ID.as("b_id"), BOOK.AUTHOR_ID.as("b_author_id"), BOOK.TITLE.as("b_title") ) .from(AUTHOR) .join(BOOK).on(BOOK.AUTHOR_ID.eq(AUTHOR.ID)) .orderBy(BOOK.ID)), "bookmapping" // The name of the SqlResultSetMapping ); result.forEach((Object[] entities) -> { JPAAuthor author = (JPAAuthor) entities[1]; JPABook book = (JPABook) entities[0]; System.out.println(author.firstName + " " + author.lastName + " wrote " + book.title); });
现在可以修改并再次持久化这些实体。
注意事项
- 我们必须按名称(字符串)引用结果集映射 - 这里没有类型安全
- 我们不知道结果
List
中包含的类型 - 存在ClassCastException
的可能性 - 结果实际上是一个
Object[]
列表,各个实体列在数组中,需要显式转换
反馈
您对此页面有任何反馈吗? 我们很乐意听到!