borinquenkid opened a new issue, #16565:
URL: https://github.com/apache/grails-core/issues/16565
## Steps to reproduce
Two domain classes, a parent with a composite identifier declared as `zeta`,
`alpha` (not in name order) and a bidirectional one-to-many to a child:
```groovy
@Entity
class Parent implements Serializable {
String zeta
String alpha
static hasMany = [kids: Kid]
static mapping = MappingBuilder.define {
composite('zeta', 'alpha')
}
}
@Entity
class Kid {
String name
static belongsTo = [parent: Parent]
}
```
```groovy
Parent.withNewTransaction {
new Parent(zeta: 'z', alpha: 'a').addToKids(new Kid(name:
'kid')).save(failOnError: true, flush: true)
}
Parent.withNewSession {
Parent.findByZetaAndAlpha('z', 'a').kids*.name // [] - expected ['kid']
}
```
The kid is saved with the right foreign key values, and `kid.parent` loads.
`parent.kids` loads no elements.
Declared as `composite('alpha', 'zeta')`, the same classes load the kids.
## Expected behaviour
`parent.kids` loads the kids in either declaration order. The declaration
order of a composite identifier is not meant to change the mapping: Hibernate
sorts the parts of a composite identifier by name, and the to-one side of the
association is aligned with that order.
## Cause
`BidirectionalOneToManyLinker.link` (`grails-data-hibernate7/core`, package
`org.grails.orm.hibernate.cfg.domainbinding.secondpass`) builds the key of the
inverse collection by copying the columns of the to-one side (`Kid.parent`).
Those columns are already in key order (`parent_alpha`, `parent_zeta`). It then
calls `key.sortProperties()`, which applies the owner identifier's permutation
a second time: the identifier declared as `zeta`, `alpha` sorts to `alpha`,
`zeta`, and the permutation moves the already sorted columns to `parent_zeta`,
`parent_alpha`. The collection is then loaded with the identifier values bound
to the wrong columns, so the query matches no rows. With `composite('alpha',
'zeta')` the permutation is the identity, which is why that order works.
The same mismatch shows in the composite chain of
`CompositeForeignKeyRegistrationOrderSpec`: with the referenced entities
registered first, `PrbMiddle.leaves` ends up with
`prb_middle_grand_parent_zeta, prb_middle_grand_parent_alpha, prb_middle_name`
while `PrbLeaf.middle` is `prb_middle_grand_parent_alpha,
prb_middle_grand_parent_zeta, prb_middle_name`. `grand.middles` and
`middle.leaves` load empty in every registration order.
It predates #16539 and does not need a nested composite; it reproduces on
8.0.x with the two classes above.
## What has been tried
Marking the copied key sorted instead of re-sorting it (so that
`sortProperties()` is a no-op on the copy). The collections then load in every
registration order except the two in which the collection's second pass runs
before the deferred alignment of the to-one it copies from
(`CompositeForeignKeySecondPass`, added in #16539): there the copied columns
are still in declared order, so the copy would have to align the to-one first,
before copying its columns. That is the same ordering the deferred alignment
already handles for the keys that reference an identifier, so the fix belongs
with it.
## Why it is deferred
#16539 fixes the foreign keys (column names, types, order and the
registration-order dependence) and the duplicate positional key of the inverse
collection; this finding is about the columns the inverse collection is loaded
by, in `BidirectionalOneToManyLinker.link`, and was split out of that PR to
keep it reviewable. `InverseHasManyCompositeIdentifierOrderSpec`
(`grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder`)
pins the repro above as a `@PendingFeature`: the name-order variant passes,
the out-of-name-order variant is pending and will fail the build as "passes
unexpectedly" once it is fixed, at which point the annotation is to be removed.
Found by @jdaugherty while reviewing #16539 (review comment 4230978366).
--
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]