可用版本:Dev (3.21) | 最新 (3.20) | 3.19 | 3.18 | 3.17 | 3.16 | 3.15 | 3.14 | 3.13 | 3.12 | 3.11

将 jOOQ 与 JPA EntityResult 结合使用

适用于 ✅ 开源版   ✅ 专业版   ✅ 企业版

这些章节的目标是描述如何在您有充分理由的情况下这样做。然而,大多数情况下,最好直接使用 jOOQ 执行查询,特别是如果您想使用 jOOQ 更高级的功能。这篇博文说明了直接使用 jOOQ 执行查询的各种原因

虽然 JPA 指定了如何实现映射(例如,使用 jakarta.persistence.SqlResultSetMapping),但对于您如何生成 SQL 语句没有任何限制。以下简单示例展示了如何从 jOOQ 生成的 SQL 语句中生成 JPABookJPAAuthor 实体(来自上一节)。

为此,我们需要指定 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")
            }
        )
    }
)

请注意,我们需要在以下之间进行映射

有了上面的样板代码,我们现在可以使用 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[] 列表,各个实体列在数组中,需要显式转换

反馈

您对此页面有任何反馈吗? 我们很乐意听到!

The jOOQ Logo