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


##########
grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionKeyBinderSpec.groovy:
##########
@@ -18,6 +18,7 @@
  */
 package org.grails.orm.hibernate.cfg.domainbinding.secondpass
 
+import 
org.grails.orm.hibernate.cfg.domainbinding.binder.CompositeIdentifierToManyToOneBinder

Review Comment:
   Duplicate import: the same class is imported again on line 24. CodeNarc's 
`DuplicateImport` rule is enabled but the style tasks skip test sources, so 
this is a cleanup rather than a gate failure.



##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BidirectionalOneToManyLinker.java:
##########
@@ -67,6 +81,20 @@ public void link(
             key.addColumn(mappingColumn);
             key.getTable().addColumn(mappingColumn);
         }
-        key.sortProperties();
+        key.setSorted(true);

Review Comment:
   Non-blocking. A sentence in the class javadoc that this flag is required, 
not only a way to skip the sort, would protect it from a later simplification: 
`MappingModelCreationHelper.getPropertyOrder` asserts the collection key is 
sorted and, when it is not, maps the key's columns through the identifier 
component's original property order. With this line removed, 
`InverseHasManyCompositeIdentifierOrderSpec` fails in `initializationError` 
with that `AssertionError` while the session factory is built.



##########
grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BidirectionalOneToManyLinkerSpec.groovy:
##########
@@ -80,4 +87,72 @@ class BidirectionalOneToManyLinkerSpec extends 
HibernateGormDatastoreSpec {
         !key.isForeignKeyEnabled()
         !key.isConstrained()
     }
+
+    void "the copied key is marked sorted so Hibernate does not apply the 
identifier permutation to it again"() {
+        given:
+        def metadataContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        RootClass rootClass = new RootClass(metadataContext)
+        rootClass.setEntityName("TestEntity")
+        Table table = new Table("test_table")
+        rootClass.setTable(table)
+        Property otherSideProperty = new Property()
+        otherSideProperty.setName("owner")
+        BasicValue value = new BasicValue(metadataContext, table)
+        value.addColumn(new Column("owner_id"))
+        otherSideProperty.setValue(value)
+        rootClass.addProperty(otherSideProperty)
+        Collection collection = new Bag(metadataContext, rootClass)
+        DependantValue key = new DependantValue(metadataContext, new 
Table("collection_table"), null)
+        HibernateToManyProperty otherSide = Mock(HibernateToManyProperty)
+        otherSide.getName() >> "owner"
+
+        when:
+        linker.link(collection, rootClass, key, otherSide)
+
+        then:
+        key.isSorted()
+        0 * binder._
+    }
+
+    void "the to-one side is aligned with the identifier of the owner before 
its columns are copied"() {
+        given:
+        def metadataContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        RootClass rootClass = new RootClass(metadataContext)
+        rootClass.setEntityName("TestEntity")
+        Table table = new Table("test_table")
+        rootClass.setTable(table)
+        ManyToOne toOneValue = new ManyToOne(metadataContext, table)
+        toOneValue.addColumn(new Column("owner_alpha"))
+        toOneValue.addColumn(new Column("owner_zeta"))
+        Property otherSideProperty = new Property()
+        otherSideProperty.setName("owner")
+        otherSideProperty.setValue(toOneValue)
+        rootClass.addProperty(otherSideProperty)
+        Collection collection = new Bag(metadataContext, rootClass)
+        DependantValue key = new DependantValue(metadataContext, new 
Table("collection_table"), null)
+        HibernateCompositeIdentity compositeId = 
Mock(HibernateCompositeIdentity)
+        GrailsHibernatePersistentEntity ownerEntity = 
Mock(GrailsHibernatePersistentEntity) {
+            getHibernateCompositeIdentity() >> Optional.of(compositeId)
+        }
+        HibernateManyToOneProperty otherSide = 
Mock(HibernateManyToOneProperty) {
+            getName() >> "owner"
+            getHibernateAssociatedEntity() >> ownerEntity
+        }
+        List<String> columnsWhenAligned = null
+
+        when:
+        linker.link(collection, rootClass, key, otherSide)
+
+        then: 'the to-one side is aligned once, before the key exists'
+        1 * binder.alignWithReferencedIdentifier(otherSide, toOneValue, 
compositeId, ownerEntity) >> {
+            columnsWhenAligned = key.columns*.name
+        }
+        columnsWhenAligned == []
+
+        and: 'the key copies the aligned columns and Hibernate leaves their 
order alone'
+        key.columns*.name == ['owner_alpha', 'owner_zeta']
+        key.isSorted()
+        key.sortProperties() == null

Review Comment:
   Non-blocking. For a key that wraps `null`, this assertion and the column 
check after it hold with or without `setSorted(true)`: 
`DependantValue.sortProperties()` only permutes columns when the wrapped value 
is a `SortableValue`, so here it returns null and leaves the columns alone 
either way. To make the `and:` label true, give the key an embedded `Component` 
prototype whose properties are declared out of name order (say `zeta`, `alpha`, 
with `setEmbedded(true)`): `sortProperties()` then returns a real permutation, 
and the assertion fails on a key the linker did not mark sorted and passes on 
one it did. The integration specs cover the behavior end to end, so this is 
only about what the unit test proves.



##########
grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/CollectionSecondPassBinderSpec.groovy:
##########
@@ -20,6 +20,7 @@
 package org.grails.orm.hibernate.cfg.domainbinding.secondpass
 
 
+import 
org.grails.orm.hibernate.cfg.domainbinding.binder.CompositeIdentifierToManyToOneBinder

Review Comment:
   Same here: duplicate of the import on line 39.



##########
grails-data-hibernate7/core/src/test/groovy/org/grails/orm/hibernate/cfg/domainbinding/secondpass/BidirectionalOneToManyLinkerSpec.groovy:
##########
@@ -80,4 +87,72 @@ class BidirectionalOneToManyLinkerSpec extends 
HibernateGormDatastoreSpec {
         !key.isForeignKeyEnabled()
         !key.isConstrained()
     }
+
+    void "the copied key is marked sorted so Hibernate does not apply the 
identifier permutation to it again"() {
+        given:
+        def metadataContext = 
getGrailsDomainBinder().getMetadataBuildingContext()
+        RootClass rootClass = new RootClass(metadataContext)
+        rootClass.setEntityName("TestEntity")
+        Table table = new Table("test_table")
+        rootClass.setTable(table)
+        Property otherSideProperty = new Property()
+        otherSideProperty.setName("owner")
+        BasicValue value = new BasicValue(metadataContext, table)
+        value.addColumn(new Column("owner_id"))
+        otherSideProperty.setValue(value)
+        rootClass.addProperty(otherSideProperty)
+        Collection collection = new Bag(metadataContext, rootClass)
+        DependantValue key = new DependantValue(metadataContext, new 
Table("collection_table"), null)
+        HibernateToManyProperty otherSide = Mock(HibernateToManyProperty)
+        otherSide.getName() >> "owner"
+
+        when:
+        linker.link(collection, rootClass, key, otherSide)
+
+        then:
+        key.isSorted()

Review Comment:
   Non-blocking. `key.isSorted()` was true under the old `sortProperties()` 
call too, since that call sets the flag, so this feature passes on 8.0.x 
unchanged. The note on the `sortProperties() == null` assertion below has a 
shape that tells the two apart.



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