borinquenkid opened a new pull request, #16574:
URL: https://github.com/apache/grails-core/pull/16574

   ## Problem
   
   An inverse `hasMany` on an entity with a composite identifier that is not 
declared in name order loads no elements. With `composite('zeta', 'alpha')` and 
`static hasMany = [kids: Kid]` (`Kid belongsTo = [parent: Parent]`), 
`parent.kids` is empty while `kid.parent` loads. With `composite('alpha', 
'zeta')` it works. In the three level `PrbGrand`/`PrbMiddle`/`PrbLeaf` chain, 
`grand.middles` and `middle.leaves` loaded empty in every registration order.
   
   `BidirectionalOneToManyLinker.link` copies the columns of the to-one side, 
which the composite foreign key alignment of #16539 has put in identifier order 
already, and then called `key.sortProperties()`, which applied the owner 
identifier's permutation a second time. The collection key therefore ended up 
in a different column order than the to-one key (`prb_middle_grand_parent_zeta, 
prb_middle_grand_parent_alpha, prb_middle_name` against `..._alpha, ..._zeta, 
..._name`), so the identifier values were bound to the wrong columns. The 
analysis is jdaugherty's, from the review of #16539.
   
   ## Impact
   
   Hibernate 7 on 8.0.x: any inverse `hasMany`/`oneToMany` whose owner has a 
composite identifier declared out of name order silently loads an empty 
collection. Saving and the to-one side are unaffected. Single column 
identifiers and identifiers declared in name order are unaffected, and the DDL 
does not change.
   
   ## Fix
   
   The linker marks the copied key as sorted instead of re-sorting it, so the 
collection key ends with exactly the column order and types of the to-one side. 
The collection's second pass can run before the deferred 
`CompositeForeignKeySecondPass` of the to-one side (two of the registration 
orders of the chain), so the linker first calls the idempotent 
`alignWithReferencedIdentifier` on the to-one side, which does nothing when it 
is aligned already. The result is independent of the registration order. 
`BidirectionalOneToManyLinker` takes the `CompositeIdentifierToManyToOneBinder` 
for this.
   
   ## Tests
   
   Red before the fix, green after (all 14 new iterations failed with the 
collection empty: the simple parent/kid case in both registration orders, the 
chain in all 6 and the hub children in all 6):
   
   - `InverseHasManyCompositeIdentifierOrderSpec`: the previously 
`@PendingFeature` case is now a plain feature over the 2 registration 
permutations of `IhmParent`/`IhmKid`; it saves, reloads in a new session and 
asserts the kids, and that the collection key columns equal the to-one foreign 
key columns in order. The name-order case still passes (3 tests).
   - `CompositeForeignKeyRegistrationOrderSpec`: two new features. The three 
level chain over the 6 permutations of `PrbGrand`/`PrbMiddle`/`PrbLeaf` asserts 
`grand.middles` and `middle.leaves` load after save and a session clear and are 
keyed like their to-one side. The hub layout (`PrbHub`, multi-column nested 
part between plain parts, `PrbHubChild`) over the 6 permutations asserts the 
children load and are keyed like the hub key. The spec now runs 49 iterations.
   - `BidirectionalOneToManyLinkerSpec`: two new unit features (the copy is 
marked sorted and Hibernate does not permute it again; the to-one side is 
aligned once, before the key copies its columns). `CollectionKeyBinderSpec` and 
`CollectionSecondPassBinderSpec` use the new constructor.
   - `:grails-data-hibernate7-core:test` passes in full (3714 tests, 0 
failures, 15 skipped), `checkstyleMain` and `codenarcMain` are clean. 
`CompositeForeignKeyColumnTypesSpec` and the existing foreign key and DDL specs 
are unchanged and pass.
   
   Fixes #16565
   
   🤖 Generated with [Claude Code](https://claude.com/claude-code)
   


-- 
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