2.2.3. Mapping identifier properties
The
@Id
annotation lets you define which property is the identifier of your entity bean. This property can be set by the application itself or be generated by Hibernate (preferred). You can define the identifier generation strategy thanks to the @GeneratedValue
annotation:
- AUTO - either identity column, sequence or table depending on the underlying DB
- TABLE - table holding the id
- IDENTITY - identity column
- SEQUENCE - sequence
Hibernate provides more id generators than the basic EJB3 ones. Check Section 2.4, “Hibernate Annotation Extensions” for more informations.
The following example shows a sequence generator using the SEQ_STORE configuration (see below)
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE") public Integer getId() { ... }
The next example uses the identity generator:
@Id @GeneratedValue(strategy=GenerationType.IDENTITY) public Long getId() { ... }
The
AUTO
generator is the preferred type for portable applications (across several DB vendors). The identifier generation configuration can be shared for several @Id
mappings with the generator attribute. There are several configurations available through @SequenceGenerator
and @TableGenerator
. The scope of a generator can be the application or the class. Class-defined generators are not visible outside the class and can override application level generators. Application level generators are defined at XML level (see Chapter 3, Overriding metadata through XML):
<table-generator name="EMP_GEN" table="GENERATOR_TABLE" pk-column-name="key" value-column-name="hi" pk-column-value="EMP" allocation-size="20"/> //and the annotation equivalent @javax.persistence.TableGenerator( name="EMP_GEN", table="GENERATOR_TABLE", pkColumnName = "key", valueColumnName = "hi" pkColumnValue="EMP", allocationSize=20 ) <sequence-generator name="SEQ_GEN" sequence-name="my_sequence" allocation-size="20"/> //and the annotation equivalent @javax.persistence.SequenceGenerator( name="SEQ_GEN", sequenceName="my_sequence", allocationSize=20 )
If JPA XML (like
META-INF/orm.xml
) is used to define thegenerators, EMP_GEN
and SEQ_GEN
are application level generators. EMP_GEN
defines a table based id generator using the hilo algorithm with a max_lo
of 20. The hi value is kept in a table
"GENERATOR_TABLE
". The information is kept in a row where pkColumnName
"key" is equals to pkColumnValue
"EMP
" and column valueColumnName
"hi
" contains the the next high value used.
SEQ_GEN
defines a sequence generator using a sequence named my_sequence
. The allocation size used for this sequence based hilo algorithm is 20. Note that this version of Hibernate Annotations does not handle initialValue
in the sequence generator. The default allocation size is 50, so if you want to use a sequence and pickup the value each time, you must set the allocation size to 1.
Note
Package level definition is no longer supported by the EJB 3.0 specification. However, you can use the
@GenericGenerator
at the package level (see Section 2.4.Identifier, “Identifier”).
The next example shows the definition of a sequence generator in a class scope:
@Entity @javax.persistence.SequenceGenerator( name="SEQ_STORE", sequenceName="my_sequence" ) public class Store implements Serializable { private Long id; @Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE") public Long getId() { return id; } }
This class will use a sequence named my_sequence and the SEQ_STORE generator is not visible in other classes. Note that you can check the Hibernate Annotations tests in the org.hibernate.test.annotations.id package for more examples.
You can define a composite primary key through several syntaxes:
- annotate the component property as @Id and make the component class @Embeddable
- annotate the component property as @EmbeddedId
- annotate the class as @IdClass and annotate each property of the entity involved in the primary key with @Id
While quite common to the EJB2 developer,
@IdClass
is likely new for Hibernate users. The composite primary key class corresponds to multiple fields or properties of the entity class, and the names of primary key fields or properties in the primary key class and those of the entity class must match and their types must be the same. Let's look at an example:
@Entity @IdClass(FootballerPk.class) public class Footballer { //part of the id key @Id public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } //part of the id key @Id public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public String getClub() { return club; } public void setClub(String club) { this.club = club; } //appropriate equals() and hashCode() implementation } @Embeddable public class FootballerPk implements Serializable { //same name and type as in Footballer public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } //same name and type as in Footballer public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } //appropriate equals() and hashCode() implementation }
As you may have seen,
@IdClass
points to the corresponding primary key class.
While not supported by the EJB3 specification, Hibernate allows you to define associations inside a composite identifier. Simply use the regular annotations for that
@Entity @AssociationOverride( name="id.channel", joinColumns = @JoinColumn(name="chan_id") ) public class TvMagazin { @EmbeddedId public TvMagazinPk id; @Temporal(TemporalType.TIME) Date time; } @Embeddable public class TvMagazinPk implements Serializable { @ManyToOne public Channel channel; public String name; @ManyToOne public Presenter presenter; }