=== modified file 'src/com/goldencode/p2j/persist/AdaptiveQuery.java'
--- old/src/com/goldencode/p2j/persist/AdaptiveQuery.java	2022-10-05 08:54:36 +0000
+++ new/src/com/goldencode/p2j/persist/AdaptiveQuery.java	2022-11-09 10:12:47 +0000
@@ -335,6 +335,9 @@
 **                           the scopeable is 'active' (i.e. unnamed streams or accumulators are used).  This
 **                           allows a lazy registration of scopeables, to avoid the unnecessary overhead of
 **                           processing all the scopeables for each and every block.
+**     RAA 20221010          Added method isAutoFetch() for when lazy fetching is intended.
+**     RAA 20221027          Added a 'get' method with a LazyFetching parameter for when lazy fetching
+**                           is intended.
 */
 
 /*
@@ -3276,6 +3279,11 @@
    protected void fetch(boolean available, LockType lockType, boolean errorIfNull)
    throws MissingRecordException
    {
+      if (available && getResults().isAutoFetch())
+      {
+         return;
+      }
+
       super.fetch(available, lockType, errorIfNull);
       
       if (!isScrolling() && !foundFirst && available && offEnd == OffEnd.NONE)
@@ -3790,20 +3798,52 @@
       }
       
       /**
+       * Is the result delegate responsible for fetching? This is usually true when using
+       * query delegates which handle the fetching process already.
+       * 
+       * @return   {@code true} for complex results which also do the fetching
+       * 
+       */
+      @Override
+      public boolean isAutoFetch()
+      {
+         return true;
+      }
+      
+      /**
        * Get the array of objects at the current result row.
        *
        * @return  Object array or <code>null</code>.
        */
       public Object[] get()
       {
-         int len = buffers.length;
-         Object[] row = new Object[len];
-         for (int i = 0; i < len; i++)
+         return get(null);
+      }
+      
+      /**
+       * Get the array of objects at the current result row if lazy fetching allows it.
+       *
+       * @param   fetching
+       *          The instance responsible with lazy fetching.
+       * @return  Object array or <code>null</code>.
+       */
+      public Object[] get(LazyFetching fetching)
+      {
+         // if lazy fetching is not intended at all or
+         // if lazy fetching is intended and getting the full record is OK
+         if (fetching == null || fetching.isFullRecordOk())
          {
-            row[i] = get(i);
+            int len = buffers.length;
+            Object[] row = new Object[len];
+            for (int i = 0; i < len; i++)
+            {
+               row[i] = get(i);
+            }
+            
+            return row;
          }
          
-         return row;
+         throw new IllegalStateException("Lazy Fetching is used, but the record is already hydrated");
       }
       
       /**

=== modified file 'src/com/goldencode/p2j/persist/PreselectQuery.java'
--- old/src/com/goldencode/p2j/persist/PreselectQuery.java	2022-10-13 18:29:04 +0000
+++ new/src/com/goldencode/p2j/persist/PreselectQuery.java	2022-11-09 10:17:54 +0000
@@ -585,6 +585,8 @@
 **     OM  20220530          Fixed flush of nursery (only the affected index).
 **     OM  20220701          Flatten calls to initialize().
 **     CA  20221006          Added JMX instrumentation for query assemble. Refs #6814
+**     RAA 20221010          Added class PreselectLazyFetching which enables the possibility of lazy fetching
+**                           for Preselect queries on temporary no-undo tables.
 **     CA  20221013          In 'repositionByID', if the row number is after the last row in the ResultSet,
 **                           assume an error (query off-end) and do not try to fetch the record.
 */
@@ -762,6 +764,9 @@
    /** Has query been registered for resource cleanup? */
    private boolean regCleaner = false;
    
+   /** Instance of lazy fetching. */
+   private LazyFetching fetching = new PreselectLazyFetching();
+   
    /** Cleaner executed when this query's block is exit. */
    private final Finalizable cleaner = new Finalizable()
    {
@@ -5669,8 +5674,11 @@
          }
          else
          {
-            Object[] data = available ? results.get() : null;
-            coreFetch(data, lockType, errorIfNull, false);
+            if (!results.isAutoFetch())
+            {
+               Object[] data = available ? results.get(fetching) : null;
+               coreFetch(data, lockType, errorIfNull, false);
+            }   
             
             if (available)
             {
@@ -5732,10 +5740,18 @@
    {
       int recFetched = 0;
       Iterator<QueryComponent> iter = components();
+      
       for (int i = 0; iter.hasNext(); i++)
       {
          QueryComponent comp = iter.next();
          RecordBuffer buffer = comp.getBuffer();
+
+         if (data != null && data[i] == null)
+         {
+            recFetched++;
+            continue;
+         }
+         
          boolean dirtyCopy = false;
          Record dmo = null;
          LockType lt = lockType;
@@ -6669,7 +6685,30 @@
       @Override
       public Object[] get()
       {
-         return (cursor == 0) ? new Object[] { templateRowid } : null; 
+         return get(null);
+      }
+      
+      /**
+       * Get the array of objects at the current result row if lazy fetching allows it.
+       *
+       * @param   fetching
+       *          The instance responsible with lazy fetching.
+       * @return  Object array or {@code null}.
+       */
+      @Override
+      public Object[] get(LazyFetching fetching)
+      {
+         if (cursor != 0)
+            return null;
+         
+         // if lazy fetching is not intended at all or
+         // if lazy fetching is intended and getting the full record is OK
+         if (fetching == null || fetching.isFullRecordOk())
+         {
+            return new Object[] { templateRowid };
+         }
+         
+         throw new IllegalStateException("Lazy Fetching is used, but the record is already hydrated");
       }
       
       /**
@@ -6791,5 +6830,68 @@
          // else cursor is -1 (before), 0 (on single record), 1 (after)
       }
    }
+   
+   /**
+    * Class that implements the concept of {@link LazyFetching} for {@link PreselectQuery}.
+    * It provides a quick response as to whether a {@link Record} should be lazy fetched or not.
+    */
+   class PreselectLazyFetching
+   implements LazyFetching
+   {
+
+      /**
+       * Method to check if a {@link Record} should be fully/partially fetched or not.
+       * Fully fetched means that a {@code Record} should be retrieved from the database,
+       * partially fetched means that a {@code Record} should be retrieved from the cache.
+       * This method does not make the difference between fully and partially fetching. It only matters if
+       * the lazy fetching layer is being bypassed or not (what happens after that is not its job).
+       * 
+       * This implementation is specific to this class because we compare the primary key of the existing
+       * record with the one that is about to be put in the {@link RecordBuffer}.
+       * For other types of Queries different implementations could be required.
+       * 
+       * @param   comp
+       *          The number of the {@link QueryComponent} for which we check it's {@link RecordBuffer}.
+       * @param   id
+       *          The id of the {@code Record} that is about to be put in the {@code RecordBuffer}.
+       * @return  {@code true} if a {@code Record} should be fully/partially fetched 
+       *          (does not matter which one), {@code false} otherwise.
+       */
+      @Override
+      public boolean shouldFetch(int comp, Long id)
+      {
+         QueryComponent component = components.get(comp);
+         return component.checkFetching(id);
+      }
+
+      /**
+       * Setter for the {@code oldId}, which is responsible with knowing the id of the
+       * last {@code Record} that was inside the {@link RecordBuffer}.
+       * 
+       * @param   comp
+       *          The number of the {@link QueryComponent} for which we check it's {@code RecordBuffer}.
+       * @param   id
+       *          The id of the old {@code Record}.
+       */
+      @Override
+      public void setOldId(int comp, Long id)
+      {
+         components.get(comp).setOldId(id);
+      }
+
+      /**
+       * Method for checking if it is OK to retrieve the full record. Most of the times, the implementation
+       * of this method will return {@code true}. Only in very few cases, the retrieval of the full record
+       * will not benefit the cause.
+       * 
+       * @return  {@code true} if we are fine with working with the full record, {@code false} otherwise.  
+       */
+      @Override
+      public boolean isFullRecordOk()
+      {
+         return true;
+      }
+      
+   }
 }
 

=== modified file 'src/com/goldencode/p2j/persist/PresortCompoundQuery.java'
--- old/src/com/goldencode/p2j/persist/PresortCompoundQuery.java	2020-09-06 23:15:41 +0000
+++ new/src/com/goldencode/p2j/persist/PresortCompoundQuery.java	2022-11-09 10:12:47 +0000
@@ -30,6 +30,8 @@
 ** 012 OM  20180620          Added support for dynamically configured sort criteria.
 ** 013 ECF 20181106          Added runtime support for {FIRST|LAST}-OF methods.
 ** 014 ECF 20200906          New ORM implementation.
+** 015 RAA 20221027          Added a 'get' method with a LazyFetching parameter for when lazy fetching
+**                           is intended.
 */
 
 /*
@@ -90,6 +92,7 @@
 import java.io.*;
 import java.util.*;
 import com.goldencode.p2j.persist.lock.*;
+import com.goldencode.p2j.persist.orm.*;
 import com.goldencode.p2j.util.*;
 
 /**
@@ -651,7 +654,26 @@
        */
       public Object[] get()
       {
-         return row;
+         return get(null);
+      }
+      
+      /**
+       * Get the array of objects at the current result row if lazy fetching allows it.
+       *
+       * @param   fetching
+       *          The instance responsible with lazy fetching.
+       * @return  Object array or <code>null</code>.
+       */
+      public Object[] get(LazyFetching fetching)
+      {
+         // if lazy fetching is not intended at all or
+         // if lazy fetching is intended and getting the full record is OK
+         if (fetching == null || fetching.isFullRecordOk())
+         {
+            return row;
+         }
+         
+         throw new IllegalStateException("Lazy Fetching is used, but the record is already hydrated");   
       }
       
       /**

=== modified file 'src/com/goldencode/p2j/persist/Presorter.java'
--- old/src/com/goldencode/p2j/persist/Presorter.java	2021-09-23 13:39:02 +0000
+++ new/src/com/goldencode/p2j/persist/Presorter.java	2022-11-09 10:12:47 +0000
@@ -34,6 +34,8 @@
 ** 016 ECF 20190427          Fixed results caching.
 ** 017 ECF 20200906          New ORM implementation.
 ** 018 CA  20210923          Fixed SortedResults, when the component retrieves only the DMO id.
+** 019 RAA 20221027          Added a 'get' method with a LazyFetching parameter for when lazy fetching
+**                           is intended.
 */
 
 /*
@@ -96,6 +98,7 @@
 import java.util.function.*;
 import com.goldencode.p2j.util.*;
 import com.goldencode.p2j.persist.event.SessionListener;
+import com.goldencode.p2j.persist.orm.*;
 
 /**
  * This helper class performs client-side (i.e., relative to the database
@@ -934,15 +937,33 @@
        */
       public Object[] get()
       {
+         return get(null);
+      }
+      
+      /**
+       * Get the array of objects at the current result row if lazy fetching allows it.
+       *
+       * @param   fetching
+       *          The instance responsible with lazy fetching.
+       * @return  Object array or <code>null</code>.
+       */
+      public Object[] get(LazyFetching fetching)
+      {
          if (scrolling)
          {
-            return super.get();
+            return super.get(fetching);
          }
          else
          {
-            Object[] datum = (Object[]) currentRow;
-            
-            return datum;
+            // if lazy fetching is not intended at all or
+            // if lazy fetching is intended and getting the full record is OK
+            if (fetching == null || fetching.isFullRecordOk())
+            {
+               Object[] datum = (Object[]) currentRow;
+               return datum;
+            }
+
+            throw new IllegalStateException("Record is not hydrated and should be, in order to be used");
          }
       }
       

=== modified file 'src/com/goldencode/p2j/persist/ProgressiveResults.java'
--- old/src/com/goldencode/p2j/persist/ProgressiveResults.java	2022-08-08 13:03:07 +0000
+++ new/src/com/goldencode/p2j/persist/ProgressiveResults.java	2022-11-09 10:12:47 +0000
@@ -138,6 +138,8 @@
 **     EVL 20190822          Adding NPE protection for isResultSetCached.
 ** 039 ECF 20200419          Removed Hibernate dependencies.
 ** 040 IAS 20220720          Fixed iteration logic (multiple iterations in different directions).
+** 041 RAA 20221010          Added a 'get' method with a LazyFetching parameter for when lazy fetching
+**                           is intended.
 */
 
 /*
@@ -199,6 +201,7 @@
 import java.util.*;
 import java.util.logging.*;
 import com.goldencode.p2j.persist.event.*;
+import com.goldencode.p2j.persist.orm.*;
 import com.goldencode.p2j.util.*;
 import com.goldencode.p2j.util.ErrorManager;
 
@@ -459,13 +462,29 @@
     */
    public Object[] get()
    {
+      return get(null);
+   }
+   
+   /**
+    * Get the array of objects at the current result row.
+    *
+    * @param   fetching
+    *          The instance responsible with lazy fetching. 
+    * @return  Object array or <code>null</code>.
+    */
+   public Object[] get(LazyFetching fetching)
+   {
       if (position < 0)
       {
          return null;
       }
       
+      // we can use cache if lazy fetching is not intended at all or
+      // if lazy fetching is intended and getting the full record is OK
+      boolean canUseCache = fetching == null || fetching.isFullRecordOk();
+      
       // If we have a cache and it contains the requested record, retrieve from the cache.
-      if (cache != null && position < cache.size())
+      if (canUseCache && cache != null && position < cache.size())
       {
          return cache.get(position);
       }
@@ -476,7 +495,7 @@
          Results results = getResults(bracket);
          if (results != null)
          {
-            return results.get();
+            return results.get(fetching);
          }
       }
       catch (Exception exc)

=== modified file 'src/com/goldencode/p2j/persist/QueryComponent.java'
--- old/src/com/goldencode/p2j/persist/QueryComponent.java	2021-08-22 21:31:39 +0000
+++ new/src/com/goldencode/p2j/persist/QueryComponent.java	2022-11-09 10:12:47 +0000
@@ -28,6 +28,7 @@
 ** 014 CA  20191009 Added where and sort clause translation in case of bound buffers.
 ** 015 ECF 20200906 New ORM implementation.
 ** 016 ECF 20210820 Retrofit for query substitution parameter preprocessing fixes.
+** 017 RAA 20221010 Added the possibility of checking if fetching is necessary for this component.
 */
 
 /*
@@ -164,6 +165,9 @@
    /** Index information string as it is returned by INDEX-INFORMATION. */
    private String indexInfo = null;
    
+   /** The id of the old Record that was in the buffer. */
+   private Long oldId = null;
+   
    /**
     * The list of dynamic filters. These are filters added dynamically, at runtime and can also be
     * removed dynamically.
@@ -828,6 +832,41 @@
    }
    
    /**
+    * Method used for checking if fetching is necessary for this component.
+    * 
+    * @param   id
+    *          The id of the {@code Record} that will potentially be fetched.
+    * @return  true if the buffer needs to fetch this record, or false otherwise.
+    */
+   public boolean checkFetching(Long id)
+   {
+      Record record = buffer.getCurrentRecord();
+      if (record == null)
+      {
+         return true;
+      }
+      
+      Long bufferId = record.primaryKey();
+      if (bufferId != null && id.equals(bufferId) && id.equals(oldId))
+      {
+         return false;
+      }
+     
+      return true;
+   }
+   
+   /**
+    * Setter for the old record's id.
+    * 
+    * @param   id
+    *          The id of the record that was just fetched.
+    */
+   public void setOldId(Long id)
+   {
+      oldId = id;
+   }
+   
+   /**
     * Set the record buffer for this component's query.
     * 
     * @param    buffer

=== modified file 'src/com/goldencode/p2j/persist/Results.java'
--- old/src/com/goldencode/p2j/persist/Results.java	2020-09-06 23:15:41 +0000
+++ new/src/com/goldencode/p2j/persist/Results.java	2022-11-09 10:12:47 +0000
@@ -14,6 +14,8 @@
 ** 004 ECF 20190427          Fixed results caching.
 ** 005 SVL 20191002          Added addRow.
 ** 006 ECF 20200906          New ORM implementation.
+** 007 RAA 20221010          Added a 'get' method with a LazyFetching parameter for when lazy fetching
+**                           is intended.
 */
 
 /*
@@ -71,6 +73,8 @@
 
 package com.goldencode.p2j.persist;
 
+import com.goldencode.p2j.persist.orm.*;
+
 /**
  * An abstraction layer between a joinable query implementation and its results.  This interface
  * defines methods for manipulating a results set using a scrollable cursor paradigm.  Each row
@@ -122,6 +126,18 @@
    public boolean isLast();
    
    /**
+    * Is the result delegate responsible for fetching? This is usually true when using
+    * query delegates which handle the fetching process already.
+    * 
+    * @return   {@code true} for complex results which also do the fetching.
+    * 
+    */
+   default public boolean isAutoFetch() 
+   {
+      return false;
+   }
+   
+   /**
     * Get the array of objects at the current result row.
     *
     * @return  Object array or {@code null}.
@@ -129,6 +145,24 @@
    public Object[] get();
    
    /**
+    * Get the array of objects at the current result row. The default method involves no lazy fetching.
+    * If lazy fetching is desired, then this method needs to be implemented.
+    * 
+    * @param   fetching
+    *          The instance responsible with lazy fetching.
+    * @return  Array of {@code Object}s and {@code null}s.
+    */
+   default public Object[] get(LazyFetching fetching) 
+   {
+      if (fetching != null)
+      {
+         throw new IllegalStateException(this.getClass().getName() + 
+                                         " does not implement get() with onlyDifferences.");
+      }
+      return get();
+   }
+   
+   /**
     * Get the object at the current result row, at the specified column.
     *
     * @param   column
@@ -241,4 +275,4 @@
    {
       throw new IllegalStateException("Cannot add a row for this type of results");
    }
-}
\ No newline at end of file
+}

=== modified file 'src/com/goldencode/p2j/persist/ResultsAdapter.java'
--- old/src/com/goldencode/p2j/persist/ResultsAdapter.java	2020-09-06 23:15:41 +0000
+++ new/src/com/goldencode/p2j/persist/ResultsAdapter.java	2022-11-09 10:12:47 +0000
@@ -24,6 +24,8 @@
 **                           to true.
 ** 007 ECF 20190427          Fixed results caching.
 ** 008 ECF 20200906          New ORM implementation.
+** 009 RAA 20221010          Added a 'get' method with a LazyFetching parameter for when lazy fetching
+**                           is intended.
 */
 
 /*
@@ -83,6 +85,8 @@
 
 import java.io.*;
 
+import com.goldencode.p2j.persist.orm.*;
+
 /**
  * An implementation of the {@code Results} interface which delegates all work to another {@code
  * Results} implementation.  A worker can be connected at any time using {@link #setResults}, or
@@ -203,6 +207,19 @@
    }
    
    /**
+    * Is the result delegate responsible for fetching? This is usually true when using
+    * query delegates which handle the fetching process already.
+    * 
+    * @return   {@code true} for complex results which also do the fetching.
+    * 
+    */
+   @Override
+   public boolean isAutoFetch()
+   {
+      return results.isAutoFetch();
+   }
+   
+   /**
     * Get the array of objects at the current result row.
     *
     * @return  Object array or {@code null}.
@@ -211,6 +228,18 @@
    {
       return results.get();
    }
+
+   /**
+    * Get the array of objects at the current result row if lazy fetching allows it.
+    * 
+    * @param   fetching
+    *          The instance responsible with lazy fetching.
+    * @return  Object array or {@code null}.
+    */
+   public Object[] get(LazyFetching fetching)
+   {
+      return results.get(fetching);
+   }
    
    /**
     * Get the object at the current result row, at the specified column.
@@ -405,4 +434,4 @@
          provider.provideNewResults(this);
       }
    }
-}
\ No newline at end of file
+}

=== modified file 'src/com/goldencode/p2j/persist/ScrollingResults.java'
--- old/src/com/goldencode/p2j/persist/ScrollingResults.java	2020-09-07 16:23:31 +0000
+++ new/src/com/goldencode/p2j/persist/ScrollingResults.java	2022-11-09 10:12:47 +0000
@@ -20,6 +20,8 @@
 **                           first record (and we are actually on/before the first row). But, in postgresql
 **                           JDBC driver, doing a -1 scroll will position us on the last row (it circles
 **                           back from the last row if the value is negative!).
+** 009 RAA 20221010          Added a 'get' method with a LazyFetching parameter for when lazy fetching
+**                           is intended.
 */
 
 /*
@@ -197,6 +199,18 @@
    }
    
    /**
+    * Get an array of objects or nulls at the current result row if lazy fetching allows it.
+    * 
+    * @param   fetching
+    *          The instance responsible with lazy fetching.  
+    * @return  Object array or <code>null</code>.
+    */
+   public Object[] get(LazyFetching fetching)
+   {
+      return results.get(fetching);
+   }
+   
+   /**
     * Get the object at the current result row, at the specified column.
     *
     * @param   column

=== modified file 'src/com/goldencode/p2j/persist/SimpleResults.java'
--- old/src/com/goldencode/p2j/persist/SimpleResults.java	2020-09-06 23:15:41 +0000
+++ new/src/com/goldencode/p2j/persist/SimpleResults.java	2022-11-09 10:12:47 +0000
@@ -23,6 +23,8 @@
 ** 010 ECF 20190427          Fixed results caching.
 ** 011 SVL 20191002          Added addRow.
 ** 012 ECF 20200906          New ORM implementation.
+** 013 RAA 20221010          Added a 'get' method with a LazyFetching parameter for when lazy fetching
+**                           is intended.
 */
 
 /*
@@ -82,6 +84,8 @@
 
 import java.util.*;
 
+import com.goldencode.p2j.persist.orm.*;
+
 /**
  * A simple implementation of {@code Results} which stores row data in a list provided to the
  * constructor. The row data consists of a list of array objects. Each object in the array is
@@ -209,11 +213,26 @@
     */
    public Object[] get()
    {
+      return get(null);
+   }
+   
+   /**
+    * Get the array of objects at the current result row.
+    * Because {@code SimpleResults} is meant to provide database results as fast as possible,
+    * checks for Lazy Fetching are skipped here 
+    * (which also means that future implementations of Lazy Fetching here will not be considered).
+    *
+    * @param   fetching
+    *          The instance responsible with lazy fetching.
+    * @return  Object array or {@code null}.
+    */
+   public Object[] get(LazyFetching fetching)
+   {
       if (position < 0 || position > getNumberOfLoadedRows() - 1)
       {
          return null;
       }
-      
+
       Object res = rows.get(position);
       if (res instanceof Object[])
       {
@@ -223,7 +242,8 @@
       {
           return new Object[] { res };
       }
-   }
+      
+   } 
    
    /**
     * Get the object at the current result row, at the specified column.

=== added file 'src/com/goldencode/p2j/persist/orm/LazyFetching.java'
--- old/src/com/goldencode/p2j/persist/orm/LazyFetching.java	1970-01-01 00:00:00 +0000
+++ new/src/com/goldencode/p2j/persist/orm/LazyFetching.java	2022-11-03 12:09:26 +0000
@@ -0,0 +1,113 @@
+/*
+** Module   : LazyFetching.java
+** Abstract : A layer between a Query and Results.
+**
+** Copyright (c) 2004-2022, Golden Code Development Corporation.
+**
+** -#- -I- --Date-- -----------------------------------Description-----------------------------------
+** 001 RAA 20221010 Added the concept of lazy fetching. This stands between the Query and its Results.
+*                   If the Query wishes to apply lazy fetching, then this interface needs to be implemented.
+*                   Implementations might differ, depending on how the results are being retrieved.
+*                            
+*/
+
+/*
+** This program is free software: you can redistribute it and/or modify
+** it under the terms of the GNU Affero General Public License as
+** published by the Free Software Foundation, either version 3 of the
+** License, or (at your option) any later version.
+**
+** This program is distributed in the hope that it will be useful,
+** but WITHOUT ANY WARRANTY; without even the implied warranty of
+** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+** GNU Affero General Public License for more details.
+**
+** You may find a copy of the GNU Affero GPL version 3 at the following
+** location: https://www.gnu.org/licenses/agpl-3.0.en.html
+** 
+** Additional terms under GNU Affero GPL version 3 section 7:
+** 
+**   Under Section 7 of the GNU Affero GPL version 3, the following additional
+**   terms apply to the works covered under the License.  These additional terms
+**   are non-permissive additional terms allowed under Section 7 of the GNU
+**   Affero GPL version 3 and may not be removed by you.
+** 
+**   0. Attribution Requirement.
+** 
+**     You must preserve all legal notices or author attributions in the covered
+**     work or Appropriate Legal Notices displayed by works containing the covered
+**     work.  You may not remove from the covered work any author or developer
+**     credit already included within the covered work.
+** 
+**   1. No License To Use Trademarks.
+** 
+**     This license does not grant any license or rights to use the trademarks
+**     Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
+**     of Golden Code Development Corporation. You are not authorized to use the
+**     name Golden Code, FWD, or the names of any author or contributor, for
+**     publicity purposes without written authorization.
+** 
+**   2. No Misrepresentation of Affiliation.
+** 
+**     You may not represent yourself as Golden Code Development Corporation or FWD.
+** 
+**     You may not represent yourself for publicity purposes as associated with
+**     Golden Code Development Corporation, FWD, or any author or contributor to
+**     the covered work, without written authorization.
+** 
+**   3. No Misrepresentation of Source or Origin.
+** 
+**     You may not represent the covered work as solely your work.  All modified
+**     versions of the covered work must be marked in a reasonable way to make it
+**     clear that the modified work is not originating from Golden Code Development
+**     Corporation or FWD.  All modified versions must contain the notices of
+**     attribution required in this license.
+*/
+
+package com.goldencode.p2j.persist.orm;
+
+import com.goldencode.p2j.persist.*;
+
+/**
+ * Interface that defines the concept of lazy fetching.
+ * This process appears between a Query and the retrieval of its Results.
+ * The interface must be implemented accordingly, depending on the method of retrieving results.
+ */
+public interface LazyFetching
+{
+   /**
+    * Method to check if a {@link Record} should be fully/partially fetched or not.
+    * Fully fetched means that a {@code Record} should be retrieved from the database,
+    * partially fetched means that a {@code Record} should be retrieved from the cache.
+    * This method does not make the difference between fully and partially fetching. It only matters if
+    * the lazy fetching layer is being bypassed or not (what happens after that is not its job).
+    * 
+    * @param   comp
+    *          The number of the {@link QueryComponent} for which we check it's {@link RecordBuffer}.
+    * @param   id
+    *          The id of the {@code Record} that is about to be put in the {@code RecordBuffer}.
+    * @return  {@code true} if a {@code Record} should be fully/partially fetched 
+    *          (does not matter which one), {@code false} otherwise.
+    */
+   public boolean shouldFetch(int comp, Long id);
+   
+   /**
+    * Setter for the {@code oldId}, which is responsible with knowing the id of the
+    * last {@code Record} that was inside the {@link RecordBuffer}.
+    * 
+    * @param   comp
+    *          The number of the {@link QueryComponent} for which we check it's {@code RecordBuffer}.
+    * @param   id
+    *          The id of the old {@code Record}.
+    */
+   public void setOldId(int comp, Long id);
+   
+   /**
+    * Method for checking if it is OK to retrieve the full record. Most of the times, the implementation
+    * of this method will return {@code true}. Only in very few cases, the retrieval of the full record
+    * will not benefit the cause.
+    * 
+    * @return  {@code true} if we are fine with working with the full record, {@code false} otherwise.  
+    */
+   public boolean isFullRecordOk();
+}

=== modified file 'src/com/goldencode/p2j/persist/orm/ScrollableResults.java'
--- old/src/com/goldencode/p2j/persist/orm/ScrollableResults.java	2022-10-27 21:27:12 +0000
+++ new/src/com/goldencode/p2j/persist/orm/ScrollableResults.java	2022-11-09 10:13:03 +0000
@@ -8,6 +8,7 @@
 ** 001 ECF 20191001 Created initial version, with stubbed methods.
 **     OM  20191111 Added method implementation.
 ** 002 SBI 20220811 Added new version of get method to retrieve selected columns from a row.
+** 003 RAA 20221010 Added a 'get' method with a LazyFetching parameter for when lazy fetching is intended.
 **         20221023 Added a usage of SQLQuery.hydrateRecord(ResultSet, RowStructure, int, Session).
 */
 
@@ -108,7 +109,10 @@
     * @param   session
     *          The {@code Session} to be used.
     */
-   public ScrollableResults(Statement stmt, ResultSet rs, List<RowStructure> rowStructure, Session session)
+   public ScrollableResults(Statement stmt, 
+                            ResultSet rs, 
+                            List<RowStructure> rowStructure, 
+                            Session session)
    {
       this.stmt = stmt;
       this.rs = rs;
@@ -193,16 +197,21 @@
    }
    
    /**
-    * Obtain the full set of values on current row. An array of primary keys or full {@code Record} will be
-    * returned.
+    * Obtain the full set of values on current row. An array of primary keys or full {@code Record}s,  
+    * or {@code null}s will be returned. First two cases correspond to the need of fetching,
+    * while {@code null} means that no fetching is necessary for that component.
     * 
+    * @param   fetching
+    *          The instance responsible with lazy fetching.
+    *          
     * @return  An array of {@code Object} s if the cursor is on a valid position. Otherwise {@code null} is
     *          returned. The type of returned elements may be both {@code Long} when an array of PKs (recids)
     *          is queried or an array of full {@code Record}s. The caller is responsible for handling both
     *          cases (including hydration, if needed).
     */
-   public Object[] get()
+   public Object[] get(LazyFetching fetching)
    {
+      
       return execute(() ->
       {
          int rowSize = (rowStructure == null) ? 0 : rowStructure.size();
@@ -228,13 +237,32 @@
             ret = new Object[rowSize];
             int rsOffset = 1;
             int recCnt = 0;
+            
             for (RowStructure rowStruct : rowStructure)
             {
                int expColumnCount = rowStruct.count;
+               Long object = rs.getLong(rsOffset);
+ 
+               //if fetching is not null, lazy fetching is intended
+               if (fetching != null)
+               {
+                  if (object != null && !fetching.shouldFetch(recCnt, object))
+                  {
+                     ret[recCnt] = null;
+                     // position on next record
+                     rsOffset += expColumnCount;
+                     ++recCnt;
+                     continue;
+                  } 
+               }
+               
                try
                {
-                  ret[recCnt] =
-                     SQLQuery.hydrateRecord(rs, rowStruct, rsOffset, session);
+                  ret[recCnt] = SQLQuery.hydrateRecord(rs, rowStruct, rsOffset, session);
+                  if (fetching != null)
+                  {
+                     fetching.setOldId(recCnt, object);
+                  }
                }
                catch (PersistenceException e)
                {
@@ -251,6 +279,20 @@
    }
    
    /**
+    * Obtain the full set of values on current row. An array of primary keys or full {@code Record} will be
+    * returned.
+    * 
+    * @return  An array of {@code Object} s if the cursor is on a valid position. Otherwise {@code null} is
+    *          returned. The type of returned elements may be both {@code Long} when an array of PKs (recids)
+    *          is queried or an array of full {@code Record}s. The caller is responsible for handling both
+    *          cases (including hydration, if needed).
+    */
+   public Object[] get()
+   {
+      return get(null);
+   }
+   
+   /**
     * Obtain the selection of values on current row.
     * 
     * @param    dmoInfo

