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


##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/CreateKeyForProps.java:
##########
@@ -59,23 +66,38 @@ public void createKeyForProps(HibernatePersistentProperty 
grailsProp, String pat
         PropertyConfig mappedForm = grailsProp.getMappedForm();
 
         if (mappedForm.isUnique() && mappedForm.isUniqueWithinGroup()) {
+            if (metadataCollector.isInSecondPass()) {
+                createKeyForGroup(grailsProp, path, table, columnName, 
mappedForm);
+            } else {
+                metadataCollector.addSecondPass(persistentClasses ->

Review Comment:
   On 8.0.x, `createKeyForColumns` (the key of a composite user type property, 
from #16695) resolves its group through `addGroupColumns` inline at bind time, 
so `amount unique: 'parent'` with a composite-id `parent` declared after 
`amount` and without a `column` mapping takes the same `parent_id` fallback 
this pass removes. Please route both entry points through the deferral: a 
private method that creates the key at once when `isInSecondPass()` and 
otherwise adds the pass, called from `createKeyForProps` and 
`createKeyForColumns`.



##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/CreateKeyForProps.java:
##########
@@ -59,23 +66,38 @@ public void createKeyForProps(HibernatePersistentProperty 
grailsProp, String pat
         PropertyConfig mappedForm = grailsProp.getMappedForm();
 
         if (mappedForm.isUnique() && mappedForm.isUniqueWithinGroup()) {
+            if (metadataCollector.isInSecondPass()) {
+                createKeyForGroup(grailsProp, path, table, columnName, 
mappedForm);
+            } else {
+                metadataCollector.addSecondPass(persistentClasses ->
+                        createKeyForGroup(grailsProp, path, table, columnName, 
mappedForm));
+            }
+        }
+    }
 
-            List<Column> keyList = new ArrayList<>();
-            keyList.add(new Column(columnName));
-            List<String> propertyNames = mappedForm.getUniquenessGroup();
-            GrailsHibernatePersistentEntity owner = 
grailsProp.getHibernateOwner();
-            for (String propertyName : propertyNames) {
-                HibernatePersistentProperty otherProp = 
owner.getHibernatePropertyByName(propertyName);
-                if (otherProp == null) {
-                    throw new MappingException(
-                            owner.getJavaClass().getName() + " references an 
unknown property " + propertyName);
-                }
+    private void createKeyForGroup(
+            HibernatePersistentProperty grailsProp, String path, Table table, 
String columnName, PropertyConfig mappedForm) {
+        List<Column> keyList = new ArrayList<>();
+        keyList.add(new Column(columnName));
+        List<String> propertyNames = mappedForm.getUniquenessGroup();
+        GrailsHibernatePersistentEntity owner = grailsProp.getHibernateOwner();
+        for (String propertyName : propertyNames) {
+            HibernatePersistentProperty otherProp = 
owner.getHibernatePropertyByName(propertyName);
+            if (otherProp == null) {
+                throw new MappingException(
+                        owner.getJavaClass().getName() + " references an 
unknown property " + propertyName);
+            }
+            List<ColumnConfig> columns = 
otherProp.getHibernateMappedForm().getColumns();
+            if (columns.isEmpty()) {
+                columns = Collections.singletonList(null);
+            }
+            for (ColumnConfig column : columns) {
                 String otherColumnName =
-                        
columnNameForPropertyAndPathFetcher.getColumnNameForPropertyAndPath(otherProp, 
path, null);
+                        
columnNameForPropertyAndPathFetcher.getColumnNameForPropertyAndPath(otherProp, 
path, column);

Review Comment:
   After the merge with 8.0.x this loop and `addGroupColumns` resolve the same 
members two ways. `addGroupColumns` calls `getColumnNamesForPropertyAndPath`, 
which expands a composite user type to one name per attribute and otherwise 
returns `getColumnNameForPropertyAndPath(otherProp, path, null)`. That single 
name goes through `PropertyConfig.getColumn()`, which throws `Cannot treat 
multi-column property as a single-column property` for a member with two 
configured columns, the failure #16713 reports, and for a member whose columns 
are generated later it is the `parent_id` default. Keeping this loop instead 
and bypassing `addGroupColumns` loses the composite user type expansion for a 
group member mapped with one (`reference unique: 'amount'` in #16695).
   
   Please resolve it with one resolver: move the configured-column expansion 
into `getColumnNamesForPropertyAndPath` (a composite user type gives its 
attributes, configured columns give one name each, otherwise the single 
default) and have `createKeyForGroup` call `addGroupColumns`. The two new unit 
cases here then belong in `ColumnNameForPropertyAndPathFetcherSpec`, next to 
the composite ones, with `CreateKeyForPropsSpec` stubbing 
`getColumnNamesForPropertyAndPath` as it does on 8.0.x.



##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/binder/ColumnBinder.java:
##########
@@ -65,14 +66,16 @@ public ColumnBinder(
         this.indexBinder = indexBinder;
     }
 
-    public ColumnBinder(PersistentEntityNamingStrategy namingStrategy, Dialect 
dialect) {
+    public ColumnBinder(
+            PersistentEntityNamingStrategy namingStrategy, Dialect dialect, 
MetadataBuildingContext metadataBuildingContext) {

Review Comment:
   8.0.x already has `ColumnBinder(MetadataBuildingContext, 
PersistentEntityNamingStrategy, Dialect)` (`@since 8.0.1`) beside the 
two-argument one, so after the merge this is a second three-argument 
constructor with the same types in another order. Please drop it, take the 
collector from the existing one (a null context gives a null collector), and 
leave the two-argument constructor as it is on 8.0.x.



##########
grails-data-hibernate7/core/src/main/groovy/org/grails/orm/hibernate/cfg/domainbinding/util/CreateKeyForProps.java:
##########
@@ -35,17 +38,21 @@ public class CreateKeyForProps {
 
     private final ColumnNameForPropertyAndPathFetcher 
columnNameForPropertyAndPathFetcher;
     private final UniqueKeyForColumnsCreator uniqueKeyForColumnsCreator;
+    private final InFlightMetadataCollector metadataCollector;
 
-    public CreateKeyForProps(ColumnNameForPropertyAndPathFetcher 
columnNameForPropertyAndPathFetcher) {
-        this.columnNameForPropertyAndPathFetcher = 
columnNameForPropertyAndPathFetcher;
-        this.uniqueKeyForColumnsCreator = new UniqueKeyForColumnsCreator();
+    public CreateKeyForProps(

Review Comment:
   On 8.0.x the one-argument constructor has three callers after #16695: 
`ColumnBinder(namingStrategy, dialect)`, which passes a null 
`MetadataBuildingContext` on purpose, `CompositeUserTypeBinder`, and 
`EnumTypeBinder`. Please keep 
`CreateKeyForProps(ColumnNameForPropertyAndPathFetcher)`, with a null collector 
meaning the key is created at once, as 8.0.0 did; 3a16c6d939 kept the 8.0.0 
constructor of `CollectionSecondPassBinder` the same way. 
`CompositeUserTypeBinder` should pass the collector, or the composite path 
never defers.



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