Fix @OneToOne composite @JoinColumn handling for @EmbeddedId in JDBC - #3883
Fix @OneToOne composite @JoinColumn handling for @EmbeddedId in JDBC#3883radovanradic wants to merge 27 commits into
Conversation
…uence identities, including Postgres R2DBC placeholder numbering.
…Ds and add record-based JDBC regression coverage
…duplicate embedded-column regression tests.
There was a problem hiding this comment.
Pull request overview
This PR addresses incorrect SQL/DDL generation for owning @OneToOne relationships that use composite @JoinColumns pointing at an associated entity with an @EmbeddedId (issue #3415). The core change ensures explicit join-column names are honored (instead of derived metadata_id_* names) and that shared-identity PK/FK one-to-one mappings don’t cause duplicate/conflicting column mappings in INSERT/UPDATE/DDL.
Changes:
- Resolve explicit
@JoinColumn(name=..., referencedColumnName=...)names during SQL/DDL column name mapping, including for embedded/composite IDs. - Add shared-identity detection to avoid writing shared identity columns via relation paths (UPDATE) and to avoid duplicate/ambiguous physical columns (DDL/INSERT), while still supporting shared-sequence identity placeholder ordering.
- Add JDBC/R2DBC integration tests and processor-level SQL builder tests covering the fixed scenarios and conflict detection.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
| data-r2dbc/src/test/groovy/io/micronaut/data/r2dbc/postgres/one2one/PostgresOneToOneSharedSequenceIdentitySpec.groovy | R2DBC regression test for shared PK one-to-one with sequence identity and correct physical id reuse. |
| data-r2dbc/src/test/groovy/io/micronaut/data/r2dbc/postgres/one2one/PostgresOneToOneEmbeddedIdJoinColumnSpec.groovy | R2DBC regression test for composite join columns targeting an @EmbeddedId. |
| data-processor/src/test/groovy/io/micronaut/data/processor/sql/BuildUpdateSpec.groovy | Processor test ensuring shared-identity join columns aren’t updated via relation path. |
| data-processor/src/test/groovy/io/micronaut/data/processor/sql/BuildTableSpec.groovy | Processor test ensuring DDL doesn’t duplicate embedded-id columns for shared identity joins; plus conflict-case coverage. |
| data-processor/src/test/groovy/io/micronaut/data/processor/sql/BuildQuerySpec.groovy | Processor test for honoring explicit join column names differing from derived names in joins. |
| data-processor/src/test/groovy/io/micronaut/data/processor/sql/BuildInsertSpec.groovy | Processor tests for explicit join column usage in insert/update, shared-identity insert behavior, placeholder contiguity, and fail-fast on conflicting mappings. |
| data-model/src/main/java/io/micronaut/data/model/query/builder/sql/SqlSchemaUtils.java | DDL column emission now detects/handles allowed shared-identity column reuse and fails fast on true conflicts. |
| data-model/src/main/java/io/micronaut/data/model/query/builder/sql/SqlQueryBuilderUtils.java | Adds shared-identity and identity-column detection helpers and a shared path utility. |
| data-model/src/main/java/io/micronaut/data/model/query/builder/sql/SqlQueryBuilder.java | Refactors INSERT generation to handle shared-identity duplicates, sequence literals, and correct positional parameter numbering. |
| data-model/src/main/java/io/micronaut/data/model/query/builder/sql/AbstractSqlLikeQueryBuilder.java | Skips UPDATE SET entries for shared-identity join columns encountered via relation traversal. |
| data-model/src/main/java/io/micronaut/data/model/naming/NamingStrategy.java | Honors explicit join-column name when referencedColumnName matches the mapped/persisted property. |
| data-jdbc/src/test/java/io/micronaut/data/jdbc/h2/one2one/RecordAssetRepository.java | JDBC record-based repository used for embedded-id join-column fetch coverage. |
| data-jdbc/src/test/java/io/micronaut/data/jdbc/h2/one2one/RecordAssetMetadata.java | JDBC record entity for associated side with @EmbeddedId. |
| data-jdbc/src/test/java/io/micronaut/data/jdbc/h2/one2one/RecordAssetId.java | JDBC embeddable record id used in record-based regression test. |
| data-jdbc/src/test/java/io/micronaut/data/jdbc/h2/one2one/RecordAsset.java | JDBC record entity with composite @JoinColumns to associated @EmbeddedId. |
| data-jdbc/src/test/groovy/io/micronaut/data/jdbc/postgres/one2one/PostgresOneToOneSharedSequenceIdentitySpec.groovy | JDBC regression test for shared PK one-to-one with sequence identity on Postgres. |
| data-jdbc/src/test/groovy/io/micronaut/data/jdbc/h2/one2one/OneToOneEmbeddedIdJoinColumnSpec.groovy | JDBC regression test for save/update/fetch join with composite join columns + embedded id. |
| data-jdbc/src/test/groovy/io/micronaut/data/jdbc/h2/one2one/OneToOneEmbeddedIdJoinColumnRecordSpec.groovy | JDBC regression test for fetch join materialization with records + embedded id. |
|
|



Should fix issue
Adds a focused JDBC regression test for issue #3415 covering an owning ONE_TO_ONE association with two
@JoinColumnstargeting an@EmbeddedId. The test reproduces both failing paths from the report: insert/save and joined fetch.Fixes SQL name resolution so explicit composite
@JoinColumnnames are honored when expanding association backed embedded identifier properties, instead of synthesizing owner-side column names like metadata_container_id / metadata_asset_id. It also adjusts insert SQL generation to de-duplicate physical columns so shared-key one-to-one mappings do not emit the same owner PK columns twice.Hopefully should not introduce regression. Explicit
@JoinColumn/@JoinColumnsnames are now consistently honored for shared/composite identity mappings. If an existing schema relies on previously inferred column names, users can pin those names explicitly with@JoinColumnand@MappedPropertyinstead of changing the database schema.