4.  Object Identity

4.1. Datastore Identity
4.2. Entities as Identity Fields
4.3. Application Identity Tool
4.4. Autoassign / Identity Strategy Caveats

OpenJPA makes several enhancements to JPA's standard entity identity.

4.1.  Datastore Identity

The JPA specification requires you to declare one or more identity fields in your persistent classes. OpenJPA fully supports this form of object identity, called application identity. OpenJPA, however, also supports datastore identity. In datastore identity, you do not declare any primary key fields. OpenJPA manages the identity of your persistent objects for you through a surrogate key in the database.

You can control how your JPA datastore identity value is generated through OpenJPA's org.apache.openjpa.persistence.DataStoreId class annotation. This annotation has strategy and generator properties that mirror the same-named properties on the standard javax.persistence.GeneratedValue annotation described in Section 2.3, “ Id ” of the JPA Overview.

To retrieve the identity value of a datastore identity entity, use the OpenJPAEntityManager.getObjectId(Object entity) method. See Section 2.2, “ OpenJPAEntityManager ” for more information on the OpenJPAEntityManager.

Example 5.4.  JPA Datastore Identity Metadata

import org.apache.openjpa.persistence.*;

@Entity
@DataStoreId
public class LineItem {

    ... no @Id fields declared ...
}

Internally, OpenJPA uses the public org.apache.openjpa.util.Id class for datastore identity objects. When writing OpenJPA plugins, you can manipulate datastore identity objects by casting them to this class. You can also create your own Id instances and pass them to any internal OpenJPA method that expects an identity object.

In JPA, you will never see Id instances directly. Instead, calling OpenJPAEntityManager.getObjectId on a datastore identity object will return the Long surrogate primary key value for that object. You can then use this value in calls to EntityManager.find for subsequent lookups of the same record.

4.2.  Entities as Identity Fields

OpenJPA allows ManyToOne and OneToOne relations to be identity fields. To identify a relation field as an identity field, simply annotate it with both the @ManyToOne or @OneToOne relation annotation and the @Id identity annotation.

When finding an entity identified by a relation, pass the id of the relation to the EntityManager.find method:

Example 5.5.  Finding an Entity with an Entity Identity Field

public Delivery createDelivery(Order order) {
    Delivery delivery = new Delivery();
    delivery.setId(order);
    delivery.setDelivered(new Date());
    return delivery;
}

public Delivery findDelivery(EntityManager em, Order order) {
    // use the identity of the related instance 
    return em.find(Delivery.class, order.getId());
}

When your entity has multiple identity fields, at least one of which is a relation to another entity, you can use an identity class (see Section 2.1, “ Identity Class ” in the JPA Overview), or an embedded identity object. Identity class fields corresponding to entity identity fields should be of the same type as the related entity's identity. If an embedded identity object is used, you must annotate the relation field with both the @ManyToOne or @OneToOne relation annotation and the @MapsId annotation.

Example 5.6.  Id Class for Entity Identity Fields

@Entity
public class Order {

    @Id
    private long id;

    ... 
}

	/**
	 * LineItem uses a compound primary key. Part of the compound key 
	 * LineItemId is relation or reference to Order instance.
	**/   
@Entity
@IdClass(LineItemId.class)
public class LineItem {
    
    @Id
    private int index;

    @Id
    @ManyToOne
    private Order order;

    ...
}

public class LineItemId {

    public int index;
    public long order; // same type as identity of Order i.e Order.id
                       // also the variable name must match the name of the
                       // variable in LineItem that refers to Order.
}

In the example above, if Order had used an identity class OrderId in place of a simple long value, then the LineItemId.order field would have been of type OrderId.

Example 5.7.  Embedded Id for Entity Identity Fields

@Entity
public class Order {

    @Id
    private long id;

    ... 
}

	/**
	 * LineItem uses a compound primary key. Part of the compound key 
	 * LineItemId is relation or reference to Order instance.
	**/   
@Entity
public class LineItem {
    
    @EmbeddedId LineItemId id;

    @ManyToOne
    @MapsId("orderId")     // The value element of the MapsId annotation 
                           // must be used to specify the name of the primary
                           // key attribute to which the relationship  
                           // corresponds. If the primary key referenced by  
                           // the relationship attribute is of the same Java  
                           // type as the dependent's primary key, then the 
                           // value element is not specified.
    private Order order;

    ...
}

@Embeddable
public class LineItemId {

    public int index;
    public long orderId; 
}

In the example above, the LineItem uses an embedded id to represent its primary key. The primary key attribute corresponding to the relationship in the LineItemId must be of the same type as the primary key of the Order. The MapsId annotation must be applied to the relationship field LineItem.order.

4.3.  Application Identity Tool

If you choose to use application identity, you may want to take advantage of OpenJPA's application identity tool. The application identity tool generates Java code implementing the identity class for any persistent type using application identity. The code satisfies all the requirements the specification places on identity classes. You can use it as-is, or simply use it as a starting point, editing it to meet your needs.

Before you can run the application identity tool on a persistent class, the class must be compiled and must have complete metadata. All primary key fields must be marked as such in the metadata.

In JPA metadata, do not attempt to specify the @IdClass annotation unless you are using the application identity tool to overwrite an existing identity class. Attempting to set the value of the @IdClass to a non-existent class will prevent your persistent class from compiling. Instead, use the -name or -suffix options described below to tell OpenJPA what name to give your generated identity class. Once the application identity tool has generated the class code, you can set the @IdClass annotation.

The application identity tool can be invoked via its Java class, org.apache.openjpa.enhance.ApplicationIdTool.

Note

Section 1.3, “ Application Identity Tool Ant Task ” describes the application identity tool's Ant task.

Example 5.8.  Using the Application Identity Tool

java org.apache.openjpa.enhance.ApplicationIdTool -s Id Magazine.java

The application identity tool accepts the standard set of command-line arguments defined by the configuration framework (see Section 3, “ Command Line Configuration ”), including code formatting flags described in Section 3.1, “ Code Formatting ”. It also accepts the following arguments:

  • -directory/-d <output directory>: Path to the output directory. If the directory does not match the generated oid class' package, the package structure will be created beneath the directory. If not specified, the tool will first try to find the directory of the .java file for the persistence-capable class, and failing that will use the current directory.

  • -ignoreErrors/-i <true/t | false/f>: If false , an exception will be thrown if the tool is run on any class that does not use application identity, or is not the base class in the inheritance hierarchy (recall that subclasses never define the application identity class; they inherit it from their persistent superclass).

  • -token/-t <token>: The token to use to separate stringified primary key values in the string form of the object id. This option is only used if you have multiple primary key fields. It defaults to "::".

  • -name/-n <id class name>: The name of the identity class to generate. If this option is specified, you must run the tool on exactly one class. If the class metadata already names an object id class, this option is ignored. If the name is not fully qualified, the persistent class' package is prepended to form the qualified name.

  • -suffix/-s <id class suffix>: A string to suffix each persistent class name with to form the identity class name. This option is overridden by -name or by any object id class specified in metadata.

Each additional argument to the tool must be one of the following:

  • The full name of a persistent class.

  • The .java file for a persistent class.

  • The .class file of a persistent class.

If you do not supply any arguments to the tool, it will act on the classes in your persistent classes list (see Section 1, “ Persistent Class List ”).

4.4.  Autoassign / Identity Strategy Caveats

Section 2.4, “ Generated Value ” explains how to use JPA's IDENTITY generation type to automatically assign field values. However, here are some additional caveats you should be aware of when using IDENTITY generation:

  1. Your database must support auto-increment / identity columns, or some equivalent (see Section 4.4, “ OracleDictionary Properties ” for how to configure a combination of triggers and sequences to fake auto-increment support in Oracle database).

  2. Auto-increment / identity columns must be an integer or long integer type.

  3. Databases support auto-increment / identity columns to varying degrees. Some do not support them at all. Others only allow a single such column per table, and require that it be the primary key column. More lenient databases may allow non-primary key auto-increment columns, and may allow more than one per table. See your database documentation for details.