jdaugherty commented on code in PR #16539:
URL: https://github.com/apache/grails-core/pull/16539#discussion_r4218417671


##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/CompositeIdentifierToManyToOneBinder.java:
##########
@@ -126,7 +127,10 @@ private Optional<Stream<ColumnConfig>> 
tryExpandNestedComposite(
         if (nestedComposite == null) {
             return Optional.empty();
         }
+        // Hibernate sorts the properties of a composite identifier by name, 
and the columns this key
+        // references follow that order, so the foreign key columns are named 
in the same order
         return Optional.of(Arrays.stream(nestedComposite)
+                
.sorted(Comparator.comparing(HibernatePersistentProperty::getName))

Review Comment:
   This orders the columns inside the nested part, but the parts themselves are 
still misordered when the nested to-one is declared after a part that sorts 
before it. `sortOrIndexForeignKeyColumns` passes the property permutation from 
`Component.sortProperties()` to `SimpleValue.sortColumns`, which applies it to 
the column list. That only lines up when every part has one column. 
`getReferencedIdentifierColumns` does the same through `sortedByPermutation`.
   
   To reproduce, declare the middle entity's nested part second:
   
   ```groovy
   @Entity
   class PrbGrand implements Serializable {
       String zeta
       String alpha
       static hasMany = [middles: PrbMiddle]
       static mapping = MappingBuilder.define { composite('zeta', 'alpha') }
   }
   
   @Entity
   class PrbMiddle implements Serializable {
       String name
       static belongsTo = [grandParent: PrbGrand]
       static hasMany = [leaves: PrbLeaf]
       static mapping = MappingBuilder.define { composite('name', 
'grandParent') }
   }
   
   @Entity
   class PrbLeaf implements Serializable {
       String name
       static belongsTo = [middle: PrbMiddle]
       static mapping = MappingBuilder.define { composite('middle', 'name') }
   }
   ```
   
   The leaf's foreign key, in `KEY_SEQ` order, is 
`prb_middle_grand_parent_alpha, prb_middle_name, prb_middle_grand_parent_zeta`. 
Saving a leaf fails:
   
   ```
   Referential integrity constraint violation: "FKDEN36EQGOPJY1BD3T41V9BTYS: 
PUBLIC.PRB_LEAF FOREIGN KEY(PRB_MIDDLE_GRAND_PARENT_ALPHA, PRB_MIDDLE_NAME, 
PRB_MIDDLE_GRAND_PARENT_ZETA) REFERENCES PUBLIC.PRB_MIDDLE(PRB_GRAND_ALPHA, 
NAME, PRB_GRAND_ZETA) ('Z', 'A', 'M')"
   ```
   
   `aa54db7056` fails the same way, so this is not a regression. It is the same 
nested composite chain this PR fixes, though, and the new spec misses it 
because both middle entities declare `composite('grandParent', 'name')`, which 
is already in name order.
   
   I tried turning the property permutation into a column permutation, moving 
each part to its sorted position across its whole column span, in both 
`sortOrIndexForeignKeyColumns` and `getReferencedIdentifierColumns`. With that 
change the foreign key becomes `alpha, zeta, name`, the leaf saves and reloads, 
and the `*Composite*` specs still pass.
   
   Would you be willing to fix this in this PR? If so, a middle entity that 
declares `composite('name', 'grandParent')` in 
`CompositeForeignKeyColumnTypesSpec` would cover it, with the `KEY_SEQ` 
assertion and a save and reload.



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