![]() | ![]() |
![]() |
| Project | Ver 1.1 | Ver 1.2 | JDO | JPA | Guides | Tools |
| 1.1 | Preparation | O/R Mapping | Runtime | Extensions | Developer |
![]() JDO provides an interface to the persistence of objects. JDO 1.0 doesn't provide a way of taking an object that was just persisted and just work on it and update the persisted object later. The user has to copy the fields manually and copy them back to the persisted object later. JDO 2.0 introduces a new way of handling this situation, by detaching an object from the persistence graph, allowing it to be worked on in the users application. It can then be attached to the persistence graph later. The first thing to do to use a class with this facility is to tag it as "detachable". This is done by adding the attribute <class name="MyClass" detachable="true"> This acts as an instruction to the enhancement process to add methods necessary to utilise the attach/detach process. The following code fragment highlights how to use the attach/detach mechanism
Product working_product=null;
Transaction tx=pm.currentTransaction();
try
{
tx.begin();
Product prod=new Product(name,description,price);
pm.makePersistent(prod);
// Detach the product for use
working_product = (Product)pm.detachCopy(prod);
tx.commit();
}
catch (Exception e)
{
// Handle the exception
}
finally
{
if (tx.isActive())
{
tx.rollback();
}
}
// Work on the detached object in our application
working_product.setPrice(new_price);
...
// Reattach the updated object
tx = pm.currentTransaction();
try
{
tx.begin();
pm.makePersistent(working_product);
tx.commit();
}
catch (Exception e)
{
// Handle the exception
}
finally
{
if (tx.isActive())
{
tx.rollback();
}
}So we now don't need to do any manual copying of object fields just using a simple call to detach the object, and then attach it again later. Here are a few things to note with attach/detach :-
![]() When attaching an object graph (using makePersistent()) JPOX will, by default, make a check if each detached object has been detached from this datastore (since they could have been detached from a different datastore). This clearly can cause significant numbers of additional datastore activity with a large object graph. Consequently, from JPOX 1.1.5, we provide a PMF property org.jpox.attachSameDatastore which, when set to true, will omit these checks and assume that we are attaching to the same datastore they were detached from. To read more about attach/detach and how to use it with fetch-groups you can look at our Tutorial on DAO Layer design.
![]() JDO2 also provides a mechanism whereby all objects that were enlisted in a transaction are automatically detached when the transaction is committed. You can enable this in one of 3 ways. If you want to use this mode globally for all PersistenceManagers (PMs) from a PersistenceManagerFactory (PMF) you could either set the PMF property javax.jdo.option.DetachAllOnCommit, or you could create your PMF and call the PMF method setDetachAllOnCommit(true). If instead you wanted to use this mode only for a particular PM, or only for a particular transaction for a particular PM, then you can call the PM method setDetachAllOnCommit(true) before the commit of the transaction, and it will apply for all transaction commits thereafter, until turned off (setDetachAllOnCommit(false). Here's an example
// Create a PMF
...
// Create an object
MyObject my = new MyObject();
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try
{
tx.begin();
// We want our object to be detached when it's been persisted
pm.setDetachAllOnCommit(true);
// Persist the object that we created earlier
pm.makePersistent(my);
tx.commit();
// The object "my" is now in detached state and can be used further
}
finally
{
if (tx.isActive)
{
tx.rollback();
}
}This is present in JPOX from version 1.1.0-beta-5 onwards.
![]() A very useful backup to the above programmatic detachment of instances is that when you close your PersistenceManager you can opt to have all instances currently cached in the Level 1 Cache of that PersistenceManager detached automatically. This means that you can persist instances, and then when you close the PM the instances will be detached and ready for further work. This is a JPOX extension. You enable this by setting the PersistenceManagerFactory (PMF) property org.jpox.DetachOnClose when you create the PMF. Let's give an example
// Create a PMF with the org.jpox.DetachOnClose property set to "true"
...
// Create an object
MyObject my = new MyObject();
PersistenceManager pm = pmf.getPersistenceManager();
Transaction tx = pm.currentTransaction();
try
{
tx.begin();
// Persist the object that we created earlier
pm.makePersistent(my);
tx.commit();
pm.close();
// The object "my" is now in detached state and can be used further
}
finally
{
if (tx.isActive)
{
tx.rollback();
}
}That is about as close to transparent persistence as you will find. When the PM is closed all instances found in the L1 Cache are detached using the current FetchPlan, and so all fields in that plan for the instances in question will be detached at that time. This is present in JPOX from version 1.1.0-beta-5 onwards.
![]() When an object is detached it is typically passed to a different layer of an application and potentially changed. During the course of the operation of the system it may be required to know what is loaded in the object and what is dirty (has been changed since detaching). JPOX provides an extension to allow interrogation of the detached object. String[] loadedFieldNames = JPOXHelper.getDetachedObjectLoadedFields(obj, pm); String[] dirtyFieldNames = JPOXHelper.getDetachedObjectDirtyFields(obj, pm); So you have access to the names of the fields that were loaded when detaching the object, and also to the names of the fields that have been updated since detaching. This is present in JPOX from version 1.1.1 onwards. |