With application identity you are taking control of the specification of id's to DataNucleus. Application identity requires a primary key class (unless you have a single primary-key field in which case the PK class is provided for you), and each persistent capable class may define a different class for its primary key, and different persistent capable classes can use the same primary key class, as appropriate. With application identity the field(s) of the primary key will be present as field(s) of the class itself. To specify that a class is to use application identity, you add the following to the MetaData for the class.
<class name="MyClass" objectid-class="MyIdClass"> <field name="myPrimaryKeyField" primary-key="true"/> ... </class>
For JDO we specify the primary-key and objectid-class. The objectid-class is optional, and is the class defining the identity for this class (again, if you have a single primary-key field then you can omit it). Alternatively, if we are using annotations
@PersistenceCapable(objectIdClass=MyIdClass.class) public class MyClass { @Persistent(primaryKey="true") private long myPrimaryKeyField; }
When you have an inheritance hierarchy, you should specify the identity type in the base instantiable class for the inheritance tree. This is then used for all persistent classes in the tree. This means that you can have superclass(es) using application-identity without any identity fields/properties but using subclass-table inheritance, and then the base instantiable class is the first persistable class which has the identity field(s). |
See also :-
Using application identity requires the use of a Primary Key class. When you have a single primary-key field a built-in class is available meaning you don't need to define this class. This is referred to as SingleFieldIdentity. We strongly recommend not to specify the PK class when you have a single PK field since these built-in classes are likely more optimised. Where the class has multiple fields that form the primary key a Primary Key class must be provided.
See also :-
Where one of the fields that is primary-key of your class is a persistable object you have something known as compound identity since the identity of this class contains the identity of a related class. Please refer to the docs for Compound Identity
By choosing application identity you are controlling the process of identity generation for this class. This does not mean that you have a lot of work to do for this. JDO defines many ways of generating these identities and DataNucleus supports all of these and provides some more of its own besides.
See also :-
When using application identity, the class has associated field(s) that equate to the identity. As a result you can simply access the values for these field(s). Alternatively you could use a JDO identity-independent way
Object id = pm.getObjectId(obj);
Object id = JDOHelper.getObjectId(obj);
JDO allows implementations to support the changing of the identity of a persisted object. This is an optional feature and DataNucleus doesn't currently support it.
If you have the JDO identity then you can access the object with that identity like this
Object obj = pm.getObjectById(id);
If you are using SingleField identity then you can access it from the object class name and the key value like this
Object obj = pm.getObjectById(MyClass.class, mykey);
If you are using your own PK class then the mykey value is the toString() form of the identity of your PK class.
When you choose application identity you are defining which fields of the class are part of the primary key, and you are taking control of the specification of id's to DataNucleus. Application identity requires a primary key (PK) class, and each persistent capable class may define a different class for its primary key, and different persistent capable classes can use the same primary key class, as appropriate. If you have only a single primary-key field then there are builtin PK classes so you can forget this section. Where you have more than 1 primary key field, you would define the PK class like this
<class name="MyClass" identity-type="application" objectid-class="MyIdClass"> ... </class>
or using annotations
@PersistenceCapable(objectIdClass=MyIdClass.class) public class MyClass { ... }
You now need to define the PK class to use. This is simplified for you because if you have only one PK field then you dont need to define a PK class and you only define it when you have a composite PK.
An important thing to note is that the PK can only be made up of fields of the following Java types
Note that the types in bold are JDO standard types. Any others are DataNucleus extensions and, as always, check the specific datastore docs to see what is supported for your datastore.
The simplest way of using application identity is where you have a single PK field, and in
this case you use SingleFieldIdentity
.
mechanism. This provides a PrimaryKey and you don't need to specify the objectid-class.
Let's take an example
public class MyClass { long id; ... } <class name="MyClass" identity-type="application"> <field name="id" primary-key="true"/> ... </class>
or using annotations
@PersistenceCapable public class MyClass { @PrimaryKey long id; ... }
So we didnt specify the JDO "objectid-class". You will, of course, have to give the field a value before persisting the object, either by setting it yourself, or by using a value-strategy on that field.
If you need to create an identity of this form for use in querying via pm.getObjectById() then you can create the identities in the following way
For a "long" type : javax.jdo.identity.LongIdentity id = new javax.jdo.identity.LongIdentity(myClass, 101); For a "String" type : javax.jdo.identity.StringIdentity id = new javax.jdo.identity.StringIdentity(myClass, "ABCD");
We have shown an example above for type "long", but you can also use this for the following
short, Short - javax.jdo.identity.ShortIdentity int, Integer - javax.jdo.identity.IntIdentity long, Long - javax.jdo.identity.LongIdentity String - javax.jdo.identity.StringIdentity char, Character - javax.jdo.identity.CharIdentity byte, Byte - javax.jdo.identity.ByteIdentity java.util.Date - javax.jdo.identity.ObjectIdentity java.util.Currency - javax.jdo.identity.ObjectIdentity java.util.Locale - javax.jdo.identity.ObjectIdentity
Since there are many possible combinations of primary-key fields it is impossible for JDO to provide a series of builtin composite primary key classes. However the DataNucleus enhancer provides a mechanism for auto-generating a primary-key class for a persistable class. It follows the rules listed below and should work for all cases. Obviously if you want to tailor the output of things like the PK toString() method then you ought to define your own. The enhancer generation of primary-key class is only enabled if you don't define your own class.
If you wish to use application identity and don't want to use the "SingleFieldIdentity" builtin PK classes then you must define a Primary Key class of your own. You can't use classes like java.lang.String, or java.lang.Long directly. You must follow these rules when defining your primary key class.
Please note that if one of the fields that comprises the primary key is in itself a persistable object then you have Compound Identity and should consult the documentation for that feature which contains its own example.
Here's an example of a composite (multiple field) primary key class
@PersistenceCapable(objectIdClass=ComposedIdKey.class) public class MyClass { @PrimaryKey String field1; @PrimaryKey String field2; ... } public class ComposedIdKey implements Serializable { public String field1; public String field2; public ComposedIdKey () { } /** * Constructor accepting same input as generated by toString(). */ public ComposedIdKey(String value) { StringTokenizer token = new StringTokenizer (value, "::"); token.nextToken(); // className this.field1 = token.nextToken(); // field1 this.field2 = token.nextToken(); // field2 } public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof ComposedIdKey)) { return false; } ComposedIdKey c = (ComposedIdKey)obj; return field1.equals(c.field1) && field2.equals(c.field2); } public int hashCode () { return this.field1.hashCode() ^ this.field2.hashCode(); } public String toString () { // Give output expected by String constructor return this.getClass().getName() + "::" + this.field1 + "::" + this.field2; } }