Skip to content

Add executeWithKey() to JPAInsertClause and HibernateInsertClause#1693

Open
zio0911 wants to merge 2 commits intoOpenFeign:masterfrom
zio0911:feature/execute-with-key-jpa-1692
Open

Add executeWithKey() to JPAInsertClause and HibernateInsertClause#1693
zio0911 wants to merge 2 commits intoOpenFeign:masterfrom
zio0911:feature/execute-with-key-jpa-1692

Conversation

@zio0911
Copy link
Copy Markdown

@zio0911 zio0911 commented Apr 14, 2026

Summary

  • Add executeWithKey(Path<T>) and executeWithKey(Class<T>) to JPAInsertClause and HibernateInsertClause
  • Bypass JPQL and execute native SQL INSERT via JDBC with Statement.RETURN_GENERATED_KEYS to retrieve auto-generated keys
  • Add JpaInsertNativeHelper utility to resolve @Table/@Column annotations and build native SQL INSERT statements
  • Add doReturningWork() to SessionHolder interface and all implementations

Closes #1692

Motivation

The SQL module's SQLInsertClause supports executeWithKey(), but the JPA module does not. This forces JPA users to fall back to EntityManager.persist() + flush() for insert + key return, breaking the consistent QueryDSL style.

Using the SQL module in a JPA project requires a separate SQLQueryFactory, SQL-specific Q-classes, and managing two query factories — excessive overhead just for insert key return.

Before / After

Before — must break out of QueryDSL:

entityManager.persist(entity);
entityManager.flush();
Long seq = entity.getSeq();

After — stays in QueryDSL:

Long seq = queryFactory.insert(role)
    .set(role.name, dto.roleName())
    .set(role.status, status)
    .executeWithKey(role.seq);

Implementation

Since JPA's Query.executeUpdate() only returns affected row count, the implementation:

  1. Reads @Table / @Column annotations to build native SQL (same pattern as NativeSQLSerializer)
  2. HibernateInsertClause uses Session.doReturningWork() for JDBC access
  3. JPAInsertClause uses EntityManager.unwrap(Session.class).doReturningWork()

Limitations

  • INSERT ... SELECT subqueries are not supported (throws UnsupportedOperationException)
  • Requires explicit @Table / @Column annotations if using a custom Hibernate PhysicalNamingStrategy
  • JPAInsertClause currently relies on Hibernate as the JPA provider

Test plan

  • Unit tests for JpaInsertNativeHelper (table name resolution, column name resolution, SQL generation)
  • Integration tests for HibernateInsertClause.executeWithKey() (set style, columns/values style, class type, multiple inserts, column annotation, subquery rejection)
  • Integration tests for JPAInsertClause.executeWithKey() (same scenarios)
  • All 18 new tests pass
  • Existing tests unaffected (./mvnw -Pdev verify passes)
  • Code formatted (git-code-format pre-commit hook)

@zio0911 zio0911 force-pushed the feature/execute-with-key-jpa-1692 branch from b9a1975 to 2308d3e Compare April 14, 2026 10:10
@kamilkrzywanski
Copy link
Copy Markdown
Contributor

@zio0911 Shouldn't a similar approach to escaping table and column names as in NativeSQLSerializer be used in JpaInsertNativeHelper? See for example: getTemplates().quoteIdentifier(column.name(), precededByDot).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add executeWithKey() support to JPAInsertClause and HibernateInsertClause

2 participants