JPA : Value Generation

Fields of a class can either have the values set by you the user, or you can set DataNucleus to generate them for you. This is of particular importance with identity fields where you want unique identities. You can use this value generation process with the identity field(s) in JPA. There are many different "strategies" for generating values, as defined by the JPA specification. Some strategies are specific to a particular datastore, and some are generic. You should choose the strategy that best suits your target datastore. The available strategies are :-

See also :-


Please note that the JPA spec only requires the ability to generate values for identity fields. DataNucleus allows you to do it for any field. Please bear this in mind when considering portability.

Please note that by defining a value-strategy for a field then it will, by default, always generate a value for that field on persist. If the field can store nulls and you only want it to generate the value at persist when it is null (i.e you haven't assigned a value yourself) then you can add the extension "strategy-when-notnull" as false

AUTO

With this strategy DataNucleus will choose the most appropriate strategy for the datastore being used. If you define the field as String-based then it will choose uuid-hex. Otherwise the field is numeric in which case it chooses identity if supported, otherwise sequence if supported, otherwise increment if supported otherwise throws an exception. On RDBMS you can get the behaviour used up until DN v3.0 by specifying the persistence property datanucleus.rdbms.useLegacyNativeValueStrategy as true. For a class using application identity you need to set the value-strategy attribute on the primary key field. You can configure the Meta-Data for the class something like this

<entity class="MyClass">
    <attributes>
        <id name="myId">
            <generated-value strategy="AUTO"/>
        </id>
    </attributes>
</entity>

or using annotations

@Entity
public class MyClass
{
    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    private long myId;
    ...
}

To configure a class to use this generation using datastore identity you need to look at the @DatastoreId extension annotation or the XML <datastore-id> tag

SEQUENCE

A sequence is a user-defined database function that generates a sequence of unique numeric ids. The unique identifier value returned from the database is translated to a java type: java.lang.Long. DataNucleus supports sequences for the following datastores:

  • Oracle
  • PostgreSQL
  • SAP DB
  • DB2
  • Firebird
  • HSQLDB
  • H2
  • Derby (from v10.6)
  • SQLServer (from v2012)
  • NuoDB

To configure a class to use either of these generation methods using application identity you would add the following to the class' Meta-Data

<sequence-generator name="SEQ1" sequence-name="MY_SEQ" initial-value="5" allocation-size="10"/>
<entity class="MyClass">
    <attributes>
        <id name="myId">
            <generated-value strategy="SEQUENCE" generator="SEQ1"/>
        </id>
    </attributes>
</entity>

or using annotations

@Entity
@SequenceGenerator(name="SEQ1", sequenceName="MY_SEQ", initialValue=5, allocationSize=10)
public class MyClass
{
    @Id
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ1")
    private long myId;
    ...
}

If the sequence does not yet exist in the database at the time DataNucleus needs a new unique identifier, a new sequence is created in the database based on the JPA Meta-Data configuration. Additional properties for configuring sequences are set in the JPA Meta-Data, see the available properties below. Unsupported properties by a database are silently ignored by DataNucleus.

Property Description Required
key-database-cache-size specifies how many sequence numbers are to be preallocated and stored in memory for faster access. This is an optimization feature provided by the database No
sequence-catalog-name Name of the catalog where the sequence is. No.
sequence-schema-name Name of the schema where the sequence is. No.

To configure a class to use this generation using datastore identity you need to look at the @DatastoreId extension annotation or the XML <datastore-id> tag

This value generator will generate values unique across different JVMs


IDENTITY

Auto-increment/identity/serial are primary key columns that are populated when a row is inserted in the table. These use the databases own keywords on table creation and so rely on having the table structure either created by DataNucleus or having the column with the necessary keyword.

DataNucleus supports auto-increment/identity/serial keys for many databases including :

  • DB2 (IDENTITY)
  • MySQL (AUTOINCREMENT)
  • MSSQL (IDENTITY)
  • Sybase (IDENTITY)
  • HSQLDB (IDENTITY)
  • H2 (IDENTITY)
  • PostgreSQL (SERIAL)
  • Derby (IDENTITY)
  • MongoDB - String based
  • Neo4j - long based
  • NuoDB (IDENTITY)

This generation strategy should only be used if there is a single "root" table for the inheritance tree. If you have more than 1 root table (e.g using subclass-table inheritance) then you should choose a different generation strategy

For a class using application identity you need to set the value-strategy attribute on the primary key field. You can configure the Meta-Data for the class something like this

<entity class="MyClass">
    <attributes>
        <id name="myId">
            <generated-value strategy="IDENTITY"/>
        </id>
    </attributes>
</entity>

or using annotations

@Entity
public class MyClass
{
    @Id
    @GeneratedValue(strategy=GenerationType.IDENTITY)
    private long myId;
    ...
}

Please be aware that if you have an inheritance tree with the base class defined as using "identity" then the column definition for the PK of the base table will be defined as "AUTO_INCREMENT" or "IDENTITY" or "SERIAL" (dependent on the RDBMS) and all subtables will NOT have this identifier added to their PK column definitions. This is because the identities are assigned in the base table (since all objects will have an entry in the base table).

Please note that if using optimistic transactions, this strategy will mean that the value is only set when the object is actually persisted (i.e at flush() or commit())

To configure a class to use this generation using datastore identity you need to look at the @DatastoreId extension annotation or the XML <datastore-id> tag

This value generator will generate values unique across different JVMs


TABLE

This method is database neutral and uses a sequence table that holds an incrementing sequence value. The unique identifier value returned from the database is translated to a java type: java.lang.Long. This strategy will work with any datastore. This method require a sequence table in the database and creates one if doesn't exist.

To configure an application identity class to use this generation method you simply add this to the class' Meta-Data. If your class is in an inheritance tree you should define this for the base class only.

<entity class="MyClass">
    <attributes>
        <id name="myId">
            <generated-value strategy="TABLE"/>
        </id>
    </attributes>
</entity>

or using annotations

@Entity
public class MyClass
{
    @Id
    @GeneratedValue(strategy=GenerationType.TABLE)
    private long myId;
    ...
}

Additional properties for configuring this generator are set in the JPA Meta-Data, see the available properties below. Unsupported properties are silently ignored by DataNucleus.

Property Description Required
key-initial-value First value to be allocated. No. Defaults to 1
key-cache-size number of unique identifiers to cache. The keys are pre-allocated, cached and used on demand. If key-cache-size is greater than 1, it may generate holes in the object keys in the database, if not all keys are used. No. Default is 50
sequence-table-basis Whether to define uniqueness on the base class name or the base table name. Since there is no "base table name" when the root class has "subclass-table" this should be set to "class" when the root class has "subclass-table" inheritance No. Defaults to class, but the other option is table
sequence-name name for the sequence (overriding the "sequence-table-basis" above). The row in the table will use this in the PK column No
sequence-table-name Table name for storing the sequence. No. Defaults to SEQUENCE_TABLE
sequence-catalog-name Name of the catalog where the table is. No.
sequence-schema-name Name of the schema where the table is. No.
sequence-name-column-name Name for the column that represent sequence names. No. Defaults to SEQUENCE_NAME
sequence-nextval-column-name Name for the column that represent incremeting sequence values. No. Defaults to NEXT_VAL
table-name Name of the table whose column we are generating the value for (used when we have no previous sequence value and want a start point. No.
column-name Name of the column we are generating the value for (used when we have no previous sequence value and want a start point. No.

To configure a class to use this generation using datastore identity you need to look at the @DatastoreId extension annotation or the XML <datastore-id> tag

This value generator will generate values unique across different JVMs


Custom Value generators

JPA only provides a very restricted set of value generators. DataNucleus provides various others internally. To access these you need to use a custom annotation as follows

<entity class="MyClass">
    <attributes>
        <id name="myId">
            <generated-value strategy="uuid"/>
        </id>
    </attributes>
</entity>

or using annotations

@Entity
public class MyClass
{
    @Id
    @ValueGenerator(strategy="uuid")
    private String myId;
    ...
}

This will generate java UUID strings in the "myId" field. You can also set the "strategy" to "timestamp", "auid", "uuid-string", "uuid-hex", and "timestamp_value". Please read the JDO documentation for full details of these generators.