borinquenkid opened a new pull request, #16701: URL: https://github.com/apache/grails-core/pull/16701
> Stacked on #16686: the base is `fix/h7-multiple-hasmany-8.0.x`, so the diff is this change alone. Retarget to `8.0.x` once #16686 merges. Fixes #16699 ## What An owner with two unidirectional `hasMany` to the same class and no `joinTable` mapping shares one join table between them, with a key column each. `CollectionKeyColumnUpdater` made the key of each collection **not updatable** in that case, the rule from #10811. Hibernate 7's collection persister writes no rows for a collection whose key is not updatable, so every `addTo*` on such an owner was dropped silently, even with `failOnError: true` (the second shape of #16665, and @jdaugherty's probe on #16686). * `CollectionKeyColumnUpdater` now keeps the key nullable and **always updatable**; the sibling counting is gone. The Hibernate 5 binder made every collection key non-updatable, which Hibernate 5 tolerated; on Hibernate 7 the flag only loses data. The native generator of the 9.x branches already treats the rule as a defect and keeps the key updatable. * Hibernate creates the implicit unique key of the shared table for the **first** collection only, over its key column and the element column (`Set.createPrimaryKey` creates none when the table has one already). A row of a later collection leaves that key column null, so on a database that treats nulls as equal in a unique constraint two of its rows for one element, from two owners, are duplicates. The new `SharedJoinTableUniqueKeyBinder`, run by `GrailsSecondPass` right after `createAllKeys`, adds the key columns of every sharing collection to that unique key: the shared table of `hasMany = [roles: Role, denyRoles: Role]` ends up with `UNIQUE (owner_roles_id, owner_deny_roles_id, role_id)`. A unique key the mapping declares explicitly, a collection with a join table of its own, and a bidirectional one-to-many are left as Hibernate binds them. ## Tests * `SharedJoinTableUniqueKeyBinderSpec` (new): the unique key of a shared table, of two tables of their own, and of a bidirectional one-to-many, read from the boot metadata; both shared keys updatable. * `CollectionKeyColumnUpdaterSpec`: the shared-table case now expects an updatable key. * `MultipleUnidirectionalHasManySpec`: a role added to each of two associations sharing a table is read back through its own association; one role denied by two groups is written once per group. * Without the fix, four cases fail (both shared-table round trips, the updater case, the unique-key case). Verified: `:grails-data-hibernate7-core:test` 3,791 tests, the one failure being the Oracle container failing to start locally, green on rerun; `checkstyleMain`, `codenarcMain`, `codenarcTest` clean. ## Out of scope Two unidirectional hasMany **Lists** (or Maps) sharing a join table are a separate, pre-existing defect: the second list's primary key overwrites the first's and both index columns are NOT NULL. Until now their rows were dropped silently as well; with updatable keys the insert fails with a `DataIntegrityViolationException` instead. Filed as #16700. On the 9.x branches the native generator will need to state the same extended unique key on a shared `@JoinTable`, since Hibernate's annotation binder skips the second unique key in the same way; the differential against the classic oracle flags it at merge-up. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
