This is an automated email from the ASF dual-hosted git repository.

borinquenkid pushed a commit to branch merge-hibernate6
in repository https://gitbox.apache.org/repos/asf/grails-core.git

commit aab64f231c6d2565f4f5ad19b1f4701a52bcb507
Author: Walter Duque de Estrada <[email protected]>
AuthorDate: Wed Sep 24 21:58:07 2025 -0500

    Fixed sorting on Composite Key
---
 .../hibernate/query/GrailsHibernateQueryUtils.java | 50 +++++++++++++++++++++-
 1 file changed, 49 insertions(+), 1 deletion(-)

diff --git 
a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/GrailsHibernateQueryUtils.java
 
b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/GrailsHibernateQueryUtils.java
index be56a839fb..88fb486460 100644
--- 
a/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/GrailsHibernateQueryUtils.java
+++ 
b/grails-data-hibernate6/core/src/main/groovy/org/grails/orm/hibernate/query/GrailsHibernateQueryUtils.java
@@ -13,13 +13,21 @@ import org.hibernate.FetchMode;
 import org.hibernate.FlushMode;
 import org.hibernate.LockMode;
 import org.hibernate.query.Query;
+import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
+import org.hibernate.query.sqm.tree.expression.SqmFunction;
+
 import org.springframework.core.convert.ConversionService;
 import org.springframework.util.ReflectionUtils;
 
 import jakarta.persistence.LockModeType;
 import jakarta.persistence.criteria.*;
 import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Comparator;
 import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.stream.Stream;
 
 
 /**
@@ -200,7 +208,47 @@ public class GrailsHibernateQueryUtils {
                                  From queryRoot,
                                  CriteriaBuilder criteriaBuilder,
                                  String sort, String order, boolean 
ignoreCase) {
-        if (sort.equalsIgnoreCase(entity.getIdentity().getName())) {
+        var compositeIdSortOptional = 
Optional.ofNullable(entity.getCompositeIdentity())
+                .stream()
+                .flatMap(Arrays::stream)
+                .filter(Objects::nonNull)
+                .filter(id -> sort.equalsIgnoreCase(id.getName()))
+                .findFirst();
+
+        if (compositeIdSortOptional.isPresent()) {
+            Comparator<Order> orderComparator = new Comparator<Order>() {
+                @Override
+                public int compare(Order o1, Order o2) {
+                    String name1 = getOrderName(o1);
+                    String name2 = getOrderName(o2);
+
+                    boolean name1IsSort = name1.equalsIgnoreCase(sort);
+                    boolean name2IsSort = name2.equalsIgnoreCase(sort);
+
+                    if (name1IsSort && !name2IsSort) {
+                        return -1; // o1 (the sort property) comes first
+                    }
+                    if (!name1IsSort && name2IsSort) {
+                        return 1; // o2 (the sort property) comes first
+                    }
+                    return 0; // Maintain original order for other properties
+                }
+
+                private static String getOrderName(Order o1) {
+                    return ((SqmBasicValuedSimplePath) ((SqmFunction) 
o1.getExpression()).getArguments().get(0)).getNavigablePath().getLocalName();
+                }
+            };
+            Order[] orders = Arrays.stream(entity.getCompositeIdentity())
+                    .map(PersistentProperty::getName)
+                    .map(name ->
+                            ignoreCase ? 
criteriaBuilder.upper(queryRoot.get(name)) : queryRoot.get(name)
+                    )
+                    .map(path -> DynamicFinder.ORDER_DESC.equals(order) ? 
criteriaBuilder.desc(path) : criteriaBuilder.asc(path))
+                    .sorted(orderComparator)
+                    .toArray(Order[]::new);
+            query.orderBy(orders);
+
+        } else if (entity.getIdentity() != null && 
sort.equalsIgnoreCase(entity.getIdentity().getName())) {
             Expression path = queryRoot;
 
             if (ignoreCase) {

Reply via email to