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]

Reply via email to