Skip to content
Permalink
Browse files
Add docs for JDOQLTyped and example for using SQL.
Fix formatting to use "Java" to get colour syntaxing.
Many other improvements
  • Loading branch information
andyjefferson committed Apr 14, 2022
1 parent 3981aa6 commit 1e39766b5bb98bc6c4ac2ab03ecc1b463ca40813
Showing 13 changed files with 812 additions and 394 deletions.
@@ -5,30 +5,28 @@

[[index]]

== JDO Attach/Detachanchor:JDO_AttachDetach[]

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. Please refer to xref:state_transition.adoc[Object Lifecycle] for
where this fits in. 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

[[JDO_AttachDetach]]
== JDO Attach/Detach

JDO provides an interface to the persistence of objects.
JDO 1.0 didn'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 had to copy the fields manually and copy them back to the persisted object later.
JDO 2.0 introduced 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 could then be *attached* to the persistence graph later.
Please refer to xref:state_transition.adoc[Object Lifecycle] for where this fits in.
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

[source,xml]
....
<class name="MyClass" detachable="true">
....

This acts as an instruction to the xref:enhancement.adoc[enhancement
process] to add methods necessary to utilise the attach/detach process.
This acts as an instruction to the xref:enhancement.adoc[enhancement process] to add methods necessary to utilise the attach/detach process.

The following code fragment highlights how to use the attach/detach
mechanism
The following code fragment highlights how to use the attach/detach mechanism

[source,java]
....
Product working_product=null;
Transaction tx=pm.currentTransaction();
@@ -84,56 +82,36 @@ finally
}
....

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_ :

* Calling _detachCopy_ on an object that is not detachable will return a
*transient* instance that is a COPY of the original, so use the COPY
thereafter.
* Calling _detachCopy_ on an object that is detachable will return a
*detached* instance that is a COPY of the original, so use this COPY
thereafter
* A _detached_ object retain the id of its datastore entity. Detached
objects should be used where you want to update the objects and attach
them later (updating the associated object in the datastore. If you want
to create copies of the objects in the datastore with their own
identities you should use _makeTransient_ instead of _detachCopy_.
* Calling _detachCopy_ will detach all fields of that object that are in
the current xref:fetchgroups.adoc[Fetch Group] for that class for that
_PersistenceManager_.
* By default the fields of the object that will be detached are those in
the _Default Fetch Group_.
* You should choose your xref:fetchgroups.adoc[Fetch Group] carefully,
bearing in mind which object(s) you want to access whilst detached.
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_ :

* Calling _detachCopy_ on an object that is not detachable will return a *transient* instance that is a COPY of the original, so use the COPY thereafter.
* Calling _detachCopy_ on an object that is detachable will return a *detached* instance that is a COPY of the original, so use this COPY thereafter
* A _detached_ object retain the id of its datastore entity.
Detached objects should be used where you want to update the objects and attach them later (updating the associated object in the datastore.
If you want to create copies of the objects in the datastore with their own identities you should use _makeTransient_ instead of _detachCopy_.
* Calling _detachCopy_ will detach all fields of that object that are in the current xref:fetchgroups.adoc[Fetch Group] for that class for that _PersistenceManager_.
* By default the fields of the object that will be detached are those in the _Default Fetch Group_.
* You should choose your xref:fetchgroups.adoc[Fetch Group] carefully, bearing in mind which object(s) you want to access whilst detached.
Detaching a relation field will detach the related object as well.
* If you don't detach a field of an object, you [.underline]#cannot#
access the value for that field while the object is detached.
* If you don't detach a field of an object, you [.underline]#can# update
the value for that field while detached, and thereafter you can access
the value for that field.
* Calling _makePersistent_ will return an (attached) copy of the
detached object. It will attach all fields that were originally
detached, and will also attach any other fields that were modified
whilst detached.

anchor:detach_all_on_commit[]

=== Detach All On Commitanchor:Detach_All_On_Commit[]

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 __PersistenceManager__s (PMs) from a
_PersistenceManagerFactory_ (PMF) you could either set the PMF property
"datanucleus.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

* If you don't detach a field of an object, you [.underline]#cannot# access the value for that field while the object is detached.
* If you don't detach a field of an object, you [.underline]#can# update the value for that field while detached, and thereafter you can access the value for that field.
* Calling _makePersistent_ will return an (attached) copy of the detached object.
It will attach all fields that were originally detached, and will also attach any other fields that were modified whilst detached.

[[detach_all_on_commit]]
=== Detach All On Commit

JDO 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 __PersistenceManager__s (PMs) from a _PersistenceManagerFactory_ (PMF) you could
either set the PMF property "datanucleus.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

[source,java]
....
// Create a PMF
...
@@ -168,21 +146,17 @@ finally
{empty} +


anchor:copy_on_attach[]

=== Copy On Attachanchor:Copy_On_Attach[]
[[copy_on_attach]]
=== Copy On Attach

By default when you are attaching a detached object it will return an
attached copy of the detached object. JDO2.1 provides a new feature that
allows this attachment to just migrate the existing detached object into
attached state.
By default when you are attaching a detached object it will return an attached copy of the detached object.
JDO2.1 provides a new feature that allows this attachment to just migrate the existing detached object into attached state.

You enable this by setting the _PersistenceManagerFactory_ (PMF)
property *datanucleus.CopyOnAttach* to false. Alternatively you can use
the methods _PersistenceManagerFactory.setCopyOnAttach(boolean flag)_ or
_PersistenceManager.setCopyOnAttach(boolean flag)_. If we return to the
example at the start of this page, this now becomes
You enable this by setting the _PersistenceManagerFactory_ (PMF) property *datanucleus.CopyOnAttach* to false.
Alternatively you can use the methods _PersistenceManagerFactory.setCopyOnAttach(boolean flag)_ or _PersistenceManager.setCopyOnAttach(boolean flag)_.
If we return to the example at the start of this page, this now becomes

[source,java]
....
// Reattach the updated object
pm.setCopyOnAttach(false);
@@ -219,26 +193,23 @@ cache), then a JDOUserException will be thrown.
{empty} +


=== Serialization of Detachable classesanchor:Serialization_of_Detachable_classes[]
[[serailization]]
=== Serialization of Detachable classes

During enhancement of Detachable classes, a field called
_jdoDetachedState_ is added to the class definition. This field allows
reading and changing tracking of detached objects while they are not
managed by a PersistenceManager.
During enhancement of Detachable classes, a field called _jdoDetachedState_ is added to the class definition.
This field allows reading and changing tracking of detached objects while they are not managed by a PersistenceManager.

When serialization occurs on a Detachable object, the _jdoDetachedState_
field is written to the serialized object stream. On deserialize, this
field is written back to the new deserialized instance. This process
occurs transparently to the application. However, if deserialization
occurs with an un-enhanced version of the class, the detached state is
lost.
When serialization occurs on a Detachable object, the _jdoDetachedState_ field is written to the serialized object stream.
On deserialize, this field is written back to the new deserialized instance.
This process occurs transparently to the application.
However, if deserialization occurs with an un-enhanced version of the class, the detached state is lost.

Serialization and deserialization of Detachable classes and un-enhanced
versions of the same class is only possible if the field
_serialVersionUID_ is added. It's recommended during development of the
class, to define the _serialVersionUID_ and make the class to implement
versions of the same class is only possible if the field _serialVersionUID_ is added.
It's recommended during development of the class, to define the _serialVersionUID_ and make the class to implement
the _java.io.Serializable_ interface, as the following example:

[source,java]
....
class MyClass implements java.io.Serializable
{
@@ -7,35 +7,34 @@

== JDO Class Typesanchor:JDO_Class_Types[]

JDO provides a means of transparent persistence of objects of user
defined classes. With JDO there are actually 3 types of classes.

* *Persistence Capable* classes are classes whose instances can be
persisted to a datastore. JDO provide the mechanism for persisting these
instances, and they are core to JDO. These classes need to be _enhanced_
according to a JDO Meta-Data specification before use within a JDO
environment.
* *Persistence Aware* classes are classes that manipulate Persistence
Capable instances through direct attribute manipulation. These classes
are typically enhanced with very minimal JDO Meta-Data. The enhancement
process performs very little changes to these classes.
* *Normal* classes are classes that aren't themselves persistable, and
have no knowledge of persistence either. These classes are totally
unchanged in JDO, and require no JDO Meta-Data whatsoever.

=== PersistenceCapableanchor:PersistenceCapable[]

Classes are defined as *PersistenceCapable* either by XML MetaData, like
this
JDO provides a means of transparent persistence of objects of user defined classes.
With JDO there are actually 3 types of classes.

* *Persistence Capable* classes are classes whose instances can be persisted to a datastore.
JDO provide the mechanism for persisting these instances, and they are core to JDO.
These classes need to be _enhanced_ according to a JDO Meta-Data specification before use within a JDO environment.
* *Persistence Aware* classes are classes that manipulate PersistenceCapable instances through direct attribute manipulation.
These classes are typically enhanced with very minimal JDO Meta-Data.
The enhancement process performs very little changes to these classes.
* *Normal* classes are classes that aren't themselves persistable, and have no knowledge of persistence either.
These classes are totally unchanged in JDO, and require no JDO Meta-Data whatsoever.


[[PersistenceCapable]]
=== PersistenceCapable

Classes are defined as *PersistenceCapable*, either by XML MetaData, like this

[source,xml]
....
<class name="MyClass">
...
</class>
....

or, in JDO2.1, using Annotations. Like this
or using Annotations, like this

[source,java]
....
@PersistenceCapable
public class MyClass
@@ -47,17 +46,19 @@ public class MyClass
{empty} +


=== PersistenceAwareanchor:PersistenceAware[]
[[PersistenceAware]]
=== PersistenceAware

Classes are defined as *PersistenceAware* either by XML MetaData, like
this
Classes are defined as *PersistenceAware* either by XML MetaData, like this

[source,xml]
....
<class name="MyClass" persistence-modifier="persistence-aware"/>
....

or, in JDO2.1, using Annotations. Like this
or using Annotations, like this

[source,java]
....
@PersistenceAware
public class MyClass
@@ -7,16 +7,16 @@

[[index]]

== JDO Bytecode Enhancementanchor:JDO_Bytecode_Enhancement[]
[[JDO_Bytecode_Enhancement]]
== JDO Bytecode Enhancement

JDO defines a byte-code enhancement process that provides for dirty
detection of fields. Before a class is used at runtime it is compiled
and then "enhanced" to implement the interface _PersistenceCapable_, and
optionally also _Detachable_.
JDO defines a byte-code enhancement process that provides for dirty detection of fields.
Before a class is used at runtime it is compiled and then "enhanced" to implement the interface _PersistenceCapable_, and optionally also _Detachable_.

We can demonstrate this by taking a sample class, and seeing it before
and after enhancement. We start with the following class
We can demonstrate this by taking a sample class, and seeing it before and after enhancement.
We start with the following class

[source,java]
....
package org.apache.jdo.test;
@@ -63,12 +63,11 @@ public class A
}
....

and require it to be _PersistenceCapable_ and _Detachable_. The
enhancement process needs to intercept all updates of the fields of the
class (id, name, b) as well as add on the necessary
_PersistenceCapable_, _Detachable_ methods. After "enhancement" it
becomes
and require it to be _PersistenceCapable_ and _Detachable_.
The enhancement process needs to intercept all updates of the fields of the
class (id, name, b) as well as add on the necessary _PersistenceCapable_, _Detachable_ methods. After "enhancement" it becomes

[source,java]
....
package org.apache.jdo.test;
import java.util.BitSet;

0 comments on commit 1e39766

Please sign in to comment.