You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cayenne.apache.org by aa...@apache.org on 2026/10/14 01:09:51 UTC

(cayenne) 02/02: Do not wrap IDs in a TreeMap when assembling prefetches

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

asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/cayenne.git

commit 858fed41e903daf7b293979078d6a41d6c962bf9
Author: Andrus Adamchik <an...@objectstyle.com>
AuthorDate: Tue Oct 13 19:27:08 2026 -0400

    Do not wrap IDs in a TreeMap when assembling prefetches
    
    This is an opportunistic performance improvement
---
 .../cayenne/access/HierarchicalObjectResolver.java |  2 +-
 .../cayenne/access/PrefetchProcessorJointNode.java | 35 ++++++++++++++--------
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/cayenne/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java b/cayenne/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
index 20e40ba02..ea5cf38b7 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/HierarchicalObjectResolver.java
@@ -447,7 +447,7 @@ class HierarchicalObjectResolver {
             PrefetchProcessorJointNode processorNode = (PrefetchProcessorJointNode) node;
 
             // find existing object, if found skip further processing
-            Map<String, Object> id = processorNode.idFromFlatRow(currentFlatRow);
+            Object id = processorNode.idFromFlatRow(currentFlatRow);
             Persistent object = processorNode.getResolved(id);
             DataRow row = null;
             if (object == null) {
diff --git a/cayenne/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java b/cayenne/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java
index e109a2890..e360da4d7 100644
--- a/cayenne/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java
+++ b/cayenne/src/main/java/org/apache/cayenne/access/PrefetchProcessorJointNode.java
@@ -58,7 +58,7 @@ class PrefetchProcessorJointNode extends PrefetchProcessorNode {
 
     RSColumn[] columns;
     int[] idIndices;
-    Map<Map, Persistent> resolved;
+    Map<Object, Persistent> resolved;
     List<DataRow> resolvedRows;
 
     // the layout of this node's rows, keyed by the columns' result set names
@@ -102,23 +102,32 @@ class PrefetchProcessorJointNode extends PrefetchProcessorNode {
     }
 
     /**
-     * Returns an ObjectId map from the flat row.
+     * Returns a key of the flat row's object for {@link #getResolved(Object)} and {@link #putResolved(Object,
+     * Persistent)}: the PK value of a single-column PK, or a list of the PK values in the PK column order. The key
+     * is only meaningful within this node, as the column names are not a part of it.
      */
-    Map<String, Object> idFromFlatRow(DataRow flatRow) {
+    Object idFromFlatRow(DataRow flatRow) {
 
         // TODO: should we also check for nulls in ID (and skip such rows) - this will
         // likely be an indicator of an outer join ... and considering SQLTemplate,
         // this is reasonable to expect...
 
-        Map<String, Object> id = new TreeMap<>();
         int[] indexes = flatRow.getLayout() != null ? flatIndexes(flatRow) : null;
-        for (int idIndex : idIndices) {
-            RSColumn column = columns[idIndex];
-            Object value = indexes != null ? valueAt(flatRow, indexes[idIndex]) : flatRow.get(column.dataRowName());
-            id.put(column.rsName(), value);
+        if (idIndices.length == 1) {
+            return idValue(flatRow, indexes, idIndices[0]);
         }
 
-        return id;
+        Object[] id = new Object[idIndices.length];
+        for (int i = 0; i < id.length; i++) {
+            id[i] = idValue(flatRow, indexes, idIndices[i]);
+        }
+
+        // Arrays.asList: a value-based key, unlike List.of it allows nulls, which an outer join produces
+        return Arrays.asList(id);
+    }
+
+    private Object idValue(DataRow flatRow, int[] indexes, int idIndex) {
+        return indexes != null ? valueAt(flatRow, indexes[idIndex]) : flatRow.get(columns[idIndex].dataRowName());
     }
 
     /**
@@ -142,10 +151,10 @@ class PrefetchProcessorJointNode extends PrefetchProcessorNode {
     }
 
     /**
-     * Looks up a previously resolved object using an ObjectId map as a key. Returns null
-     * if no matching object exists.
+     * Looks up a previously resolved object by the key returned by {@link #idFromFlatRow(DataRow)}. Returns null if
+     * no matching object exists.
      */
-    Persistent getResolved(Map id) {
+    Persistent getResolved(Object id) {
         return resolved.get(id);
     }
 
@@ -153,7 +162,7 @@ class PrefetchProcessorJointNode extends PrefetchProcessorNode {
      * Registers an object in a map of resolved objects, connects this object to parent if
      * parent exists.
      */
-    void putResolved(Map id, Persistent object) {
+    void putResolved(Object id, Persistent object) {
         resolved.put(id, object);
     }