11.2. Detachable behavior

The KodoPersistenceManager exposes six methods to support detach and attach functionality:

Detaching persistent instances will create unmanaged copies of the instances. The copy mechanism is similar to serialization, with the exception that only fields in the current fetch groups are traversed. Fields that are not in the current fetch groups will be set to the Java default for their type, and will be ignored when the detached instances are later re-attached. It is important to remember that invoking the detach method does not modify the persistent instance that is the parameter of the method call; it is the return value from that invocation that is the detached and unmanaged copy.

Example 11.1. Detaching a Single Instance

import kodo.runtime.*;

...

// CLIENT:
// requests an object with a given oid
DetachExample detached = (DetachExample) getFromServer (oid);

...

// SERVER:
// detaches object and returns to client
Object oid = processClientRequest ();
KodoPersistenceManager kpm = (KodoPersistenceManager) pm;
DetachExample example = (DetachExample) kpm.getObjectById (oid, false);
DetachExample detached = (DetachExample) kpm.detach (example);
sendToClient (detached);

...

// CLIENT:
// makes some modifications and sends back to server
detached.setSomeField ("bar");
sendToServer (detached);

...

// SERVER:
// re-attaches the instance and commit the changes
DetachExample modified = (DetachExample) processClientRequest ();
kpm.currentTransaction ().begin ();
kpm.attach (modified);
kpm.currentTransaction ().commit ();

If relation-type fields need to be detached, then they need to be declared as being in the default-fetch-group, or, if the capability is available, be declared in the custom fetch groups configuration for the KodoPersistenceManager performing the detachment.

Example 11.2. Using Custom Fetch Groups for Detach

public class DetachExample
    implements java.io.Serializable
{
    private String someField;
    private DetachExampleRelation someRelation;
}


<?xml version="1.0"?>
<jdo>
  <package name="com.somecompany">
    <class name="DetachExample">
      <extension vendor-name="kodo" key="detachable" value="true"/>
      <field name="someRelation">
        <extension vendor-name="kodo" key="fetch-group" value="mygroup"/>
      </field>
    </class>
    <class name="DetachExampleRelation">
      <extension vendor-name="kodo" key="detachable" value="true"/>
    </class>
  </package>
</jdo>


import kodo.runtime.*;

...

// CLIENT:
// requests an object with a given oid
DetachExample detached = (DetachExample) getFromServer (oid);

...

// SERVER:
// detaches object and returns to client
Object oid = processClientRequest ();
KodoPersistenceManager kpm = (KodoPersistenceManager) pm;
kpm.getFetchConfiguration ().addFetchGroup ("mygroup");
DetachExample example = (DetachExample) kpm.getObjectById (oid, false);
DetachExample detached = (DetachExample) kpm.detach (example);
sendToClient (detached);

...

// CLIENT:
// makes some modifications and sends back to server
detached.setSomeField ("bar");
detached.getRelation ().setSomeOtherField ("baz");
sendToServer (detached);

...

// SERVER:
// re-attaches the instance and commit the changes
DetachExample modified = (DetachExample) processClientRequest ();
kpm.currentTransaction ().begin ();
kpm.attach (modified); // will recursively attach relation too and apply mods
kpm.currentTransaction ().commit ();

When attaching an instance whose representation has changed in the datastore since detachment, a JDOOptimisticVerificationException will be thrown upon commit or flush, just as if a normal optimistic conflict was detected. When attaching an instance that represents an object that has been deleted since detaching, or when a attaching a detached instance into a PersistenceManager that has an earlier version of the object, a JDOOptimisticVerificationException will be immediately thrown when attach is invoked. In these cases, the RollbackOnly flag will be set on the transaction.