|
As has been described in the application identity guide, 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. You specify the primary key 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
-
Primitives :
boolean
,
byte
,
char
,
int
,
long
,
short
-
java.lang :
Boolean
,
Byte
,
Character
,
Integer
,
Long
,
Short
,
String
,
Enum
, StringBuffer
-
java.math :
BigInteger
-
java.sql :
Date
,
Time
,
Timestamp
-
java.util :
Date
,
Currency
,
Locale
, TimeZone, UUID
-
java.net : URI, URL
-
javax.jdo.spi :
PersistenceCapable
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 the JDO 2
SingleFieldIdentity
.
mechanism. This
provides
a PrimaryKey for cases where you have a single PK field 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.
-
the Primary Key class must be public
-
the Primary Key class must implement Serializable
-
the Primary Key class must have a public no-arg constructor, which might be the default
constructor
-
the field types of all non-static fields in the Primary Key class must be serializable, and
are recommended to be primitive, String, Date, or Number types
-
all serializable non-static fields in the Primary Key class must be public
-
the names of the non-static fields in the Primary Key class must include the names of the
primary key fields in the JDO class, and the types of the common fields must be identical
-
the equals() and hashCode() methods of the Primary Key class must use the value(s) of all the
fields corresponding to the primary key fields in the JDO class
-
if the Primary Key class is an inner class, it must be static
-
the Primary Key class must override the toString() method defined in Object, and return a
String that can be used as the parameter of a constructor
-
the Primary Key class must provide a String constructor that returns an instance that compares
equal to an instance that returned that String by the toString() method.
-
the Primary Key class must be only used within a single inheritence tree.
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;
}
}
|
|