One aspect of identity mapping not covered in the previous section is JPA's ability to automatically assign a value to your numeric identity fields using generators. We discussed the available generator types in Section 2.2, “ Id ”. Now we show you how to define named generators.
Most databases allow you to create native sequences. These are database
structures that generate increasing numeric values. The
SequenceGenerator
annotation represents a named database sequence.
You can place the annotation on any package, entity class, persistent field
declaration (if your entity uses field access), or getter method for a
persistent property (if your entity uses property access).
SequenceGenerator
has the following properties:
String sequenceName
: The name of the database sequence. If
you do not specify the database sequence, your vendor will choose an appropriate
default.
int allocationSize
: Some databases can pre-allocate groups
of sequence values. This allows the database to service sequence requests from
cache, rather than physically incrementing the sequence with every request. This
allocation size defaults to 50.
OpenJPA allows you to use describe one of OpenJPA's built-in generator
implementations in the sequenceName
property. You can also
set the sequenceName
to system
to use the
system sequence defined by the
openjpa.Sequence
configuration property. See the Reference
Guide's Section 6, “
Generators
” for details.
The XML element for a sequence generator is sequence-generator
. Its attributes mirror the above annotation's properties:
name
sequence-name
initial-value
allocation-size
To use a sequence generator, set your GeneratedValue
annotation's strategy
property to
GenerationType.SEQUENCE
, and its generator
property
to the sequence generator's declared name. Or equivalently, set your
generated-value
XML element's strategy
attribute to
SEQUENCE
and its generator
attribute to
the generator name.
A TableGenerator
refers to a database table used to store
increasing sequence values for one or more entities. As with
SequenceGenerator
, you can place the TableGenerator
annotation on any package, entity class, persistent field
declaration (if your entity uses field access), or getter method for a
persistent property (if your entity uses property access).
TableGenerator
has the following properties:
String table
: The name of the generator table. If left
unspecified, your vendor will choose a default table.
String pkColumnName
: The name of the primary key column in
the generator table. If unspecified, your implementation will choose a default.
String valueColumnName
: The name of the column that holds
the sequence value. If unspecified, your implementation will choose a default.
String pkColumnValue
: The primary key column value of the
row in the generator table holding this sequence value. You can use the same
generator table for multiple logical sequences by supplying different
pkColumnValue
s. If you do not specify a value, the implementation
will supply a default.
int initialValue
: The value of the generator's first issued
number.
int allocationSize
: The number of values to allocate in
memory for each trip to the database. Allocating values in memory allows the JPA
runtime to avoid accessing the database for every sequence request.
This number also specifies the amount that the sequence value is incremented
each time the generator table is updated. Defaults to 50.
The XML equivalent is the table-generator
element. This
element's attributes correspond exactly to the above annotation's properties:
name
table
schema
catalog
pk-column-name
value-column-name
pk-column-value
initial-value
allocation-size
To use a table generator, set your GeneratedValue
annotation's strategy
property to
GenerationType.TABLE
, and its generator
property to
the table generator's declared name. Or equivalently, set your
generated-value
XML element's strategy
attribute to
TABLE
and its generator
attribute to the
generator name.
Let's take advantage of generators in our entity model. Here are our updated mappings.
Example 12.4. Generator Mapping
package org.mag; @Entity @IdClass(Magazine.MagazineId.class) @Table(name="MAG") public class Magazine { @Column(length=9) @Id private String isbn; @Id private String title; ... public static class MagazineId { ... } } @Entity @Table(name="ART", uniqueConstraints=@Unique(columnNames="TITLE")) @SequenceGenerator(name="ArticleSeq", sequenceName="ART_SEQ") public class Article { @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="ArticleSeq") private long id; ... } package org.mag.pub; @Entity @Table(name="COMP") public class Company { @Column(name="CID") @Id private long id; ... } @Entity @Table(name="AUTH") public class Author { @Id @GeneratedValue(strategy=GenerationType.TABLE, generator="AuthorGen") @TableGenerator(name="AuthorGen", table="AUTH_GEN", pkColumnName="PK", valueColumnName="AID") @Column(name="AID", columnDefinition="INTEGER64") private long id; ... } @Embeddable public class Address { ... } package org.mag.subscribe; @MappedSuperclass public abstract class Document { @Id @GeneratedValue(generate=GenerationType.IDENTITY) private long id; ... } @Entity @Table(schema="CNTRCT") public class Contract extends Document { ... } @Entity @Table(name="SUB", schema="CNTRCT") public class Subscription { @Id @GeneratedValue(strategy=GenerationType.IDENTITY) private long id; ... @Entity @Table(name="LINE_ITEM", schema="CNTRCT") public static class LineItem extends Contract { ... } } @Entity(name="Lifetime") public class LifetimeSubscription extends Subscription { ... } @Entity(name="Trial") public class TrialSubscription extends Subscription { ... }
The same metadata for Article
and Author
expressed in XML form:
<entity class="org.mag.Article"> <table name="ART"> <unique-constraint> <column-name>TITLE</column-name> </unique-constraint> </table> <sequence-generator name="ArticleSeq" sequence-name="ART_SEQ"/> <attributes> <id name="id"> <generated-value strategy="SEQUENCE" generator="ArticleSeq"/> </id> ... </attributes> </entity> <entity class="org.mag.pub.Author"> <table name="AUTH"/> <attributes> <id name="id"> <column name="AID" column-definition="INTEGER64"/> <generated-value strategy="TABLE" generator="AuthorGen"/> <table-generator name="AuthorGen" table="AUTH_GEN" pk-column-name="PK" value-column-name="AID"/> </id> ... </attributes> </entity>