7.3. Fetch Groups

7.3.1. Normal Default Fetch Group Behavior
7.3.2. Kodo JDO Fetch Group Behavior
7.3.3. Configuring a PersistenceManager to load Fetch Groups

The JDO specification defines a concept of a default fetch group, but it does not touch upon additional, non-default fetch groups. Kodo JDO extends the JDO specification's fetch group concept to allow multiple fetch groups in a given class. These fetch groups can be used to pool together associated fields in order to provide performance improvements over Kodo JDO's normal fetch group behavior.

7.3.1. Normal Default Fetch Group Behavior

First, let's talk about how Kodo JDO behaves when loading data with just the regular JDO default fetch group information. Imagine the following class and metadata definitions:

public class FetchGroupExample
{
    private int                  a;
    private String               b;
    private BigInteger           c;
    private Date                 d;
    private String               e;
    private String               f;
    private FetchGroupExample    g;
}
            
<?xml version="1.0"?>
<jdo>
  <package name="">
    <class name="FetchGroupExample">
      <field name="a"/>
      <field name="b"/>
      <field name="c"/>
      <field name="d"/>
      <field name="e"/>
      <field name="f"/>
      <field name="g"/>
    </class>
  </package>
</jdo>
In this example, the default fetch group behavior is left undefined for all fields. So, the default values defined in the JDO specification will be used: all fields except g will be in the default fetch group. g will be left out of the default fetch group because it is a reference to another persistence-capable object.

Kodo JDO will load all fields in the object in the initial select statement, including the primary key of g. This primary key will be loaded because the related object may already be in the PersistenceManager's cache, so we may be able to set up this relation up-front, and since we're already going to the database for all the other fields, we might as well check the primary key. In general, this behavior is ideal, since the cost of executing a select statement including the extra fields for one-one relations from the database is minimal compared to the cost of going back to the database for this information when it's needed.

However, in some situations, it is undesirable to load certain parts of an object up-front. Sometimes, a table in the database will be comprised of many columns, so selecting the extra data -- especially if the returned result set is expected to be large -- can impose a significant overhead. Imagine loading all fields in all Employee objects associated with a large company when generating a report listing all employees. All we really needed might have been employee number and name, so loading the entire object up-front could incur a quite significant amount of unneeded data to be transferred.

To improve upon this situation, the extra fields could be defined to not be in the object's default fetch group. By doing this, the developer is providing a hint to the JDO implementation that the identified data should be lazily loaded, rather than materialized at initialization time. (In the above example, had we explicitly excluded field g from the default fetch group, Kodo would not have loaded the primary key values for this field.)

Kodo JDO's handling of fields implicitly excluded from the default fetch group is a bit more complex when dealing with multiple-table class inheritance hierarchies. As mentioned above, Kodo loads the primary keys for implicitly excluded fields when selecting data from the database. This extra data loading is not performed if the column holding the data is in a table that would not otherwise be selected. That is, we do not add an extra join in order to load this data.

7.3.2. Kodo JDO Fetch Group Behavior

Kodo JDO improves upon the JDO specification's fetch group configuration options by defining a syntax for declaring extra fetch groups in addition to the default fetch group. A field can be a member of zero or one fetch groups, including the default fetch group. That is, fields in the default fetch group cannot be in an additional fetch group, and a field cannot declare itself a member of more than one fetch group.

When loading an object, fields in these custom fetch groups are not included in the initial select statements, just as if they had been left out of the default fetch group. Upon lazily loading a field, Kodo checks to see if that field declares itself to be a member of a fetch group. If so, Kodo will load all fields in that fetch group.

Additionally, it is possible to configure the PersistenceManager to use a particular fetch group or set of fetch groups when loading new objects. When this is done, Kodo loads the default fetch group plus any fields in the set of additional fetch groups specified.

So, a custom fetch group configuration for our FetchGroupExample class might look like this:

<?xml version="1.0"?>
<jdo>
  <package name="">
    <class name="FetchGroupExample">
      <field name="a" default-fetch-group="true"/>

      <field name="b" default-fetch-group="false">
        <extension vendor-name="kodo" key="fetch-group" value="g1"/>
      </field>

      <field name="c" default-fetch-group="false">
        <extension vendor-name="kodo" key="fetch-group" value="g1"/>
      </field>

      <field name="d" default-fetch-group="false">
        <extension vendor-name="kodo" key="fetch-group" value="g1"/>
      </field>

      <field name="e" default-fetch-group="false">
        <extension vendor-name="kodo" key="fetch-group" value="g2"/>
      </field>

      <field name="f" default-fetch-group="false">
        <extension vendor-name="kodo" key="fetch-group" value="g2"/>
      </field>

      <field name="g"/>
    </class>
  </package>
</jdo>
In this example, fields a and g would be loaded whenever a new object is loaded. (Only the data in column g would be loaded -- the object on the other side of this relation would not be loaded since this field is not in the default fetch group.) When lazily loading field b, fields c and d will also be loaded, because they are all in the same fetch group -- g1.

If the PersistenceManager were configured to load fetch group g2 when loading new objects, then fields e and f would be loaded along with the default fetch group members at initial load time. Also, if any relations were traversed, then the fetch groups named would be applied to the loading of the related objects.

7.3.3. Configuring a PersistenceManager to load Fetch Groups

As mentioned above, it is possible to configure a PersistenceManager to load certain fetch groups when initially loading persistence-capable objects. The simplest way to do this is to use the com.solarmetric.kodo.FetchGroups configuration property to specify a comma-separated list of fetch group names to use when loading data. Alternately, the fetch group configuration can be mutated on a per-PersistenceManager basis by using the addFetchGroup(String), addFetchGroups(String[]), removeFetchGroup(String), removeFetchGroups(String[]), String[] getFetchGroups(), and clearFetchGroups() methods in com.solarmetric.kodo.runtime.PersistenceManagerImpl.