Hibernate.orgCommunity Documentation
Object/relational mappings can be defined in three approaches:
using Java 5 annotations (via the Java Persistence 2 annotations)
using JPA 2 XML deployment descriptors (described in chapter XXX)
using the Hibernate legacy XML files approach known as hbm.xml
Annotations are split in two categories, the logical mapping annotations (describing the object model, the association between two entities etc.) and the physical mapping annotations (describing the physical schema, tables, columns, indexes, etc). We will mix annotations from both categories in the following code examples.
JPA annotations are in the javax.persistence.*
package. Hibernate specific extensions are in
org.hibernate.annotations.*
. You favorite IDE can
auto-complete annotations and their attributes for you (even without a
specific "JPA" plugin, since JPA annotations are plain Java 5
annotations).
Here is an example of mapping
package eg;
@Entity
@Table(name="cats") @Inheritance(strategy=SINGLE_TABLE)
@DiscriminatorValue("C") @DiscriminatorColumn(name="subclass", discriminatorType=CHAR)
public class Cat {
@Id @GeneratedValue
public Integer getId() { return id; }
public void setId(Integer id) { this.id = id; }
private Integer id;
public BigDecimal getWeight() { return weight; }
public void setWeight(BigDecimal weight) { this.weight = weight; }
private BigDecimal weight;
@Temporal(DATE) @NotNull @Column(updatable=false)
public Date getBirthdate() { return birthdate; }
public void setBirthdate(Date birthdate) { this.birthdate = birthdate; }
private Date birthdate;
@org.hibernate.annotations.Type(type="eg.types.ColorUserType")
@NotNull @Column(updatable=false)
public ColorType getColor() { return color; }
public void setColor(ColorType color) { this.color = color; }
private ColorType color;
@NotNull @Column(updatable=false)
public String getSex() { return sex; }
public void setSex(String sex) { this.sex = sex; }
private String sex;
@NotNull @Column(updatable=false)
public Integer getLitterId() { return litterId; }
public void setLitterId(Integer litterId) { this.litterId = litterId; }
private Integer litterId;
@ManyToOne @JoinColumn(name="mother_id", updatable=false)
public Cat getMother() { return mother; }
public void setMother(Cat mother) { this.mother = mother; }
private Cat mother;
@OneToMany(mappedBy="mother") @OrderBy("litterId")
public Set<Cat> getKittens() { return kittens; }
public void setKittens(Set<Cat> kittens) { this.kittens = kittens; }
private Set<Cat> kittens = new HashSet<Cat>();
}
@Entity @DiscriminatorValue("D")
public class DomesticCat extends Cat {
public String getName() { return name; }
public void setName(String name) { this.name = name }
private String name;
}
@Entity
public class Dog { ... }
The legacy hbm.xml approach uses an XML schema designed to be readable and hand-editable. The mapping language is Java-centric, meaning that mappings are constructed around persistent class declarations and not table declarations.
Please note that even though many Hibernate users choose to write the XML by hand, a number of tools exist to generate the mapping document. These include XDoclet, Middlegen and AndroMDA.
Here is an example mapping:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="eg">
<class name="Cat"
table="cats"
discriminator-value="C">
<id name="id">
<generator class="native"/>
</id>
<discriminator column="subclass"
type="character"/>
<property name="weight"/>
<property name="birthdate"
type="date"
not-null="true"
update="false"/>
<property name="color"
type="eg.types.ColorUserType"
not-null="true"
update="false"/>
<property name="sex"
not-null="true"
update="false"/>
<property name="litterId"
column="litterId"
update="false"/>
<many-to-one name="mother"
column="mother_id"
update="false"/>
<set name="kittens"
inverse="true"
order-by="litter_id">
<key column="mother_id"/>
<one-to-many class="Cat"/>
</set>
<subclass name="DomesticCat"
discriminator-value="D">
<property name="name"
type="string"/>
</subclass>
</class>
<class name="Dog">
<!-- mapping for Dog could go here -->
</class>
</hibernate-mapping>
We will now discuss the concepts of the mapping documents (both
annotations and XML). We will only describe, however, the document
elements and attributes that are used by Hibernate at runtime. The mapping
document also contains some extra optional attributes and elements that
affect the database schemas exported by the schema export tool (for
example, the not-null
attribute).
An entity is a regular Java object (aka POJO) which will be persisted by Hibernate.
To mark an object as an entity in annotations, use the
@Entity
annotation.
@Entity
public class Flight implements Serializable {
Long id;
@Id
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
}
That's pretty much it, the rest is optional. There are however any options to tweak your entity mapping, let's explore them.
@Table
lets you define the table the entity
will be persisted into. If undefined, the table name is the unqualified
class name of the entity. You can also optionally define the catalog,
the schema as well as unique constraints on the table.
@Entity
@Table(name="TBL_FLIGHT",
schema="AIR_COMMAND",
uniqueConstraints=
@UniqueConstraint(
name="flight_number",
columnNames={"comp_prefix", "flight_number"} ) )
public class Flight implements Serializable {
@Column(name="comp_prefix")
public String getCompagnyPrefix() { return companyPrefix; }
@Column(name="flight_number")
public String getNumber() { return number; }
}
The constraint name is optional (generated if left undefined). The
column names composing the constraint correspond to the column names as
defined before the Hibernate NamingStrategy
is
applied.
@Entity.name
lets you define the shortcut name
of the entity you can used in JP-QL and HQL queries. It defaults to the
unqualified class name of the class.
Hibernate goes beyond the JPA specification and provide additional
configurations. Some of them are hosted on
@org.hibernate.annotations.Entity
:
dynamicInsert
/
dynamicUpdate
(defaults to false): specifies that
INSERT
/ UPDATE
SQL should be
generated at runtime and contain only the columns whose values are
not null. The dynamic-update
and
dynamic-insert
settings are not inherited by
subclasses. Although these settings can increase performance in some
cases, they can actually decrease performance in others.
selectBeforeUpdate
(defaults to false):
specifies that Hibernate should never perform
an SQL UPDATE
unless it is certain that an object
is actually modified. Only when a transient object has been
associated with a new session using update()
,
will Hibernate perform an extra SQL SELECT
to
determine if an UPDATE
is actually required. Use
of select-before-update
will usually decrease
performance. It is useful to prevent a database update trigger being
called unnecessarily if you reattach a graph of detached instances
to a Session
.
polymorphisms
(defaults to
IMPLICIT
): determines whether implicit or
explicit query polymorphisms is used. Implicit
polymorphisms means that instances of the class will be returned by
a query that names any superclass or implemented interface or class,
and that instances of any subclass of the class will be returned by
a query that names the class itself. Explicit
polymorphisms means that class instances will be returned only by
queries that explicitly name that class. Queries that name the class
will return only instances of subclasses mapped. For most purposes,
the default polymorphisms=IMPLICIT
is
appropriate. Explicit polymorphisms is useful when two different
classes are mapped to the same table This allows a "lightweight"
class that contains a subset of the table columns.
persister
: specifies a custom
ClassPersister
. The persister
attribute lets you customize the persistence strategy used for the
class. You can, for example, specify your own subclass of
org.hibernate.persister.EntityPersister
, or you
can even provide a completely new implementation of the interface
org.hibernate.persister.ClassPersister
that
implements, for example, persistence via stored procedure calls,
serialization to flat files or LDAP. See
org.hibernate.test.CustomPersister
for a simple
example of "persistence" to a Hashtable
.
optimisticLock
(defaults to
VERSION
): determines the optimistic locking
strategy. If you enable dynamicUpdate
, you will
have a choice of optimistic locking strategies:
version
: check the version/timestamp
columns
all
: check all columns
dirty
: check the changed columns,
allowing some concurrent updates
none
: do not use optimistic
locking
It is strongly recommended that you use
version/timestamp columns for optimistic locking with Hibernate.
This strategy optimizes performance and correctly handles
modifications made to detached instances (i.e. when
Session.merge()
is used).
Be sure to import
@javax.persistence.Entity
to mark a class as an
entity. It's a common mistake to import
@org.hibernate.annotations.Entity
by
accident.
Some entities are not mutable. They cannot be updated or deleted
by the application. This allows Hibernate to make some minor performance
optimizations.. Use the @Immutable
annotation.
You can also alter how Hibernate deals with lazy initialization
for this class. On @Proxy
, use
lazy
=false to disable lazy fetching (not
recommended). You can also specify an interface to use for lazy
initializing proxies (defaults to the class itself): use
proxyClass
on @Proxy
.
Hibernate will initially return proxies (Javassist or CGLIB) that
implement the named interface. The persistent object will load when a
method of the proxy is invoked. See "Initializing collections and
proxies" below.
@BatchSize
specifies a "batch size" for
fetching instances of this class by identifier. Not yet loaded instances
are loaded batch-size at a time (default 1).
You can specific an arbitrary SQL WHERE condition to be used when
retrieving objects of this class. Use @Where
for
that.
In the same vein, @Check
lets you define an
SQL expression used to generate a multi-row check
constraint for automatic schema generation.
There is no difference between a view and a base table for a
Hibernate mapping. This is transparent at the database level, although
some DBMS do not support views properly, especially with updates.
Sometimes you want to use a view, but you cannot create one in the
database (i.e. with a legacy schema). In this case, you can map an
immutable and read-only entity to a given SQL subselect expression using
@org.hibernate.annotations.Subselect
:
@Entity
@Subselect("select item.name, max(bid.amount), count(*) "
+ "from item "
+ "join bid on bid.item_id = item.id "
+ "group by item.name")
@Synchronize( {"item", "bid"} ) //tables impacted
public class Summary {
@Id
public String getId() { return id; }
...
}
Declare the tables to synchronize this entity with, ensuring that
auto-flush happens correctly and that queries against the derived entity
do not return stale data. The <subselect>
is
available both as an attribute and a nested mapping element.
We will now explore the same options using the hbm.xml structure.
You can declare a persistent class using the class
element. For example:
<class name="ClassName" table="tableName" discriminator-value="discriminator_value" mutable="true|false" schema="owner" catalog="catalog" proxy="ProxyInterface" dynamic-update="true|false" dynamic-insert="true|false" select-before-update="true|false" polymorphism="implicit|explicit" where="arbitrary sql where condition" persister="PersisterClass" batch-size="N" optimistic-lock="none|version|dirty|all" lazy="(16)true|false" entity(17)-name="EntityName" check=(18)"arbitrary sql check condition" rowid=(19)"rowid" subsel(20)ect="SQL expression" abstra(21)ct="true|false" node="element-name" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
(16) |
|
(17) |
|
(18) |
|
(19) |
|
(20) |
|
(21) |
|
It is acceptable for the named persistent class to be an
interface. You can declare implementing classes of that interface using
the <subclass>
element. You can persist any
static inner class. Specify the class name using
the standard form i.e. e.g.Foo$Bar
.
Here is how to do a virtual view (subselect) in XML:
<class name="Summary">
<subselect>
select item.name, max(bid.amount), count(*)
from item
join bid on bid.item_id = item.id
group by item.name
</subselect>
<synchronize table="item"/>
<synchronize table="bid"/>
<id name="name"/>
...
</class>
The <subselect>
is available both as an
attribute and a nested mapping element.
Mapped classes must declare the primary key column of the database table. Most classes will also have a JavaBeans-style property holding the unique identifier of an instance.
Mark the identifier property with
@Id
.
@Entity
public class Person {
@Id Integer getId() { ... }
...
}
In hbm.xml, use the <id>
element which
defines the mapping from that property to the primary key column.
<id name="propertyName" type="typename" column="column_name" unsaved-value="null|any|none|undefined|id_value" access="field|property|ClassName"> node="element-name|@attribute-name|element/@attribute|." <generator class="generatorClass"/> </id>
| |
| |
| |
| |
|
If the name
attribute is missing, it is assumed
that the class has no identifier property.
The unsaved-value
attribute is almost never
needed in Hibernate3 and indeed has no corresponding element in
annotations.
You can also declare the identifier as a composite identifier. This allows access to legacy data with composite keys. Its use is strongly discouraged for anything else.
You can define a composite primary key through several syntaxes:
use a component type to represent the identifier and map it
as a property in the entity: you then annotated the property as
@EmbeddedId
. The component type has to be
Serializable
.
map multiple properties as @Id
properties: the identifier type is then the entity class itself
and needs to be Serializable
. This approach
is unfortunately not standard and only supported by
Hibernate.
map multiple properties as @Id
properties and declare an external class to be the identifier
type. This class, which needs to be
Serializable
, is declared on the entity via
the @IdClass
annotation. The identifier
type must contain the same properties as the identifier properties
of the entity: each property name must be the same, its type must
be the same as well if the entity property is of a basic type, its
type must be the type of the primary key of the associated entity
if the entity property is an association (either a
@OneToOne
or a
@ManyToOne
).
As you can see the last case is far from obvious. It has been inherited from the dark ages of EJB 2 for backward compatibilities and we recommend you not to use it (for simplicity sake).
Let's explore all three cases using examples.
Here is a simple example of
@EmbeddedId
.
@Entity
class User {
@EmbeddedId
@AttributeOverride(name="firstName", column=@Column(name="fld_firstname")
UserId id;
Integer age;
}
@Embeddable
class UserId implements Serializable {
String firstName;
String lastName;
}
You can notice that the UserId
class is
serializable. To override the column mapping, use
@AttributeOverride
.
An embedded id can itself contains the primary key of an associated entity.
@Entity
class Customer {
@EmbeddedId CustomerId id;
boolean preferredCustomer;
@MapsId("userId")
@JoinColumns({
@JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
@JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
})
@OneToOne User user;
}
@Embeddable
class CustomerId implements Serializable {
UserId userId;
String customerNumber;
//implements equals and hashCode
}
@Entity
class User {
@EmbeddedId UserId id;
Integer age;
}
@Embeddable
class UserId implements Serializable {
String firstName;
String lastName;
//implements equals and hashCode
}
In the embedded id object, the association is represented as
the identifier of the associated entity. But you can link its value
to a regular association in the entity via the
@MapsId
annotation. The
@MapsId
value correspond to the property name
of the embedded id object containing the associated entity's
identifier. In the database, it means that the
Customer.user
and the
CustomerId.userId
properties share the same
underlying column (user_fk
in this case).
The component type used as identifier must implement
equals()
and
hashCode()
.
In practice, your code only sets the
Customer.user
property and the user id value is
copied by Hibernate into the CustomerId.userId
property.
The id value can be copied as late as flush time, don't rely on it until after flush time.
While not supported in JPA, Hibernate lets you place your
association directly in the embedded id component (instead of having
to use the @MapsId
annotation).
@Entity
class Customer {
@EmbeddedId CustomerId id;
boolean preferredCustomer;
}
@Embeddable
class CustomerId implements Serializable {
@OneToOne
@JoinColumns({
@JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
@JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
})
User user;
String customerNumber;
//implements equals and hashCode
}
@Entity
class User {
@EmbeddedId UserId id;
Integer age;
}
@Embeddable
class UserId implements Serializable {
String firstName;
String lastName;
//implements equals and hashCode
}
Let's now rewrite these examples using the hbm.xml syntax.
<composite-id
name="propertyName"
class="ClassName"
mapped="true|false"
access="field|property|ClassName"
node="element-name|.">
<key-property name="propertyName" type="typename" column="column_name"/>
<key-many-to-one name="propertyName" class="ClassName" column="column_name"/>
......
</composite-id>
First a simple example:
<class name="User">
<composite-id name="id" class="UserId">
<key-property name="firstName" column="fld_firstname"/>
<key-property name="lastName"/>
</composite-id>
</class>
Then an example showing how an association can be mapped.
<class name="Customer">
<composite-id name="id" class="CustomerId">
<key-property name="firstName" column="userfirstname_fk"/>
<key-property name="lastName" column="userfirstname_fk"/>
<key-property name="customerNumber"/>
</composite-id>
<property name="preferredCustomer"/>
<many-to-one name="user">
<column name="userfirstname_fk" updatable="false" insertable="false"/>
<column name="userlastname_fk" updatable="false" insertable="false"/>
</many-to-one>
</class>
<class name="User">
<composite-id name="id" class="UserId">
<key-property name="firstName"/>
<key-property name="lastName"/>
</composite-id>
<property name="age"/>
</class>
Notice a few things in the previous example:
the order of the properties (and column) matters. It must be the same between the association and the primary key of the associated entity
the many to one uses the same columns as the primary key
and thus must be marked as read only
(insertable
and updatable
to false).
unlike with @MapsId
, the id value
of the associated entity is not transparently copied, check the
foreign
id generator for more
information.
The last example shows how to map association directly in the embedded id component.
<class name="Customer">
<composite-id name="id" class="CustomerId">
<key-many-to-one name="user">
<column name="userfirstname_fk"/>
<column name="userlastname_fk"/>
</key-many-to-one>
<key-property name="customerNumber"/>
</composite-id>
<property name="preferredCustomer"/>
</class>
<class name="User">
<composite-id name="id" class="UserId">
<key-property name="firstName"/>
<key-property name="lastName"/>
</composite-id>
<property name="age"/>
</class>
This is the recommended approach to map composite identifier. The following options should not be considered unless some constraint are present.
Another, arguably more natural, approach is to place
@Id
on multiple properties of your entity.
This approach is only supported by Hibernate (not JPA compliant) but
does not require an extra embeddable component.
@Entity
class Customer implements Serializable {
@Id @OneToOne
@JoinColumns({
@JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
@JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
})
User user;
@Id String customerNumber;
boolean preferredCustomer;
//implements equals and hashCode
}
@Entity
class User {
@EmbeddedId UserId id;
Integer age;
}
@Embeddable
class UserId implements Serializable {
String firstName;
String lastName;
//implements equals and hashCode
}
In this case Customer
is its own
identifier representation: it must implement
Serializable
and must implement
equals()
and
hashCode()
.
In hbm.xml, the same mapping is:
<class name="Customer">
<composite-id>
<key-many-to-one name="user">
<column name="userfirstname_fk"/>
<column name="userlastname_fk"/>
</key-many-to-one>
<key-property name="customerNumber"/>
</composite-id>
<property name="preferredCustomer"/>
</class>
<class name="User">
<composite-id name="id" class="UserId">
<key-property name="firstName"/>
<key-property name="lastName"/>
</composite-id>
<property name="age"/>
</class>
@IdClass
on an entity points to the
class (component) representing the identifier of the class. The
properties marked @Id
on the entity must have
their corresponding property on the @IdClass
.
The return type of search twin property must be either identical for
basic properties or must correspond to the identifier class of the
associated entity for an association.
This approach is inherited from the EJB 2 days and we recommend against its use. But, after all it's your application and Hibernate supports it.
@Entity
@IdClass(CustomerId.class)
class Customer implements Serializable {
@Id @OneToOne
@JoinColumns({
@JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
@JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
})
User user;
@Id String customerNumber;
boolean preferredCustomer;
}
class CustomerId implements Serializable {
UserId user;
String customerNumber;
//implements equals and hashCode
}
@Entity
class User {
@EmbeddedId UserId id;
Integer age;
//implements equals and hashCode
}
@Embeddable
class UserId implements Serializable {
String firstName;
String lastName;
//implements equals and hashCode
}
Customer
and
CustomerId
do have the same properties
customerNumber
as well as
user
. CustomerId
must be
Serializable
and implement
equals()
and
hashCode()
.
While not JPA standard, Hibernate let's you declare the
vanilla associated property in the
@IdClass
.
@Entity
@IdClass(CustomerId.class)
class Customer implements Serializable {
@Id @OneToOne
@JoinColumns({
@JoinColumn(name="userfirstname_fk", referencedColumnName="firstName"),
@JoinColumn(name="userlastname_fk", referencedColumnName="lastName")
})
User user;
@Id String customerNumber;
boolean preferredCustomer;
}
class CustomerId implements Serializable {
@OneToOne User user;
String customerNumber;
//implements equals and hashCode
}
@Entity
class User {
@EmbeddedId UserId id;
Integer age;
//implements equals and hashCode
}
@Embeddable
class UserId implements Serializable {
String firstName;
String lastName;
}
This feature is of limited interest though as you are likely
to have chosen the @IdClass
approach to stay
JPA compliant or you have a quite twisted mind.
Here are the equivalent on hbm.xml files:
<class name="Customer">
<composite-id class="CustomerId" mapped="true">
<key-many-to-one name="user">
<column name="userfirstname_fk"/>
<column name="userlastname_fk"/>
</key-many-to-one>
<key-property name="customerNumber"/>
</composite-id>
<property name="preferredCustomer"/>
</class>
<class name="User">
<composite-id name="id" class="UserId">
<key-property name="firstName"/>
<key-property name="lastName"/>
</composite-id>
<property name="age"/>
</class>
Hibernate can generate and populate identifier values for you automatically. This is the recommended approach over "business" or "natural" id (especially composite ids).
Hibernate offers various generation strategies, let's explore the most common ones first that happens to be standardized by JPA:
IDENTITY: supports identity columns in DB2, MySQL, MS SQL
Server, Sybase and HypersonicSQL. The returned identifier is of
type long
, short
or
int
.
SEQUENCE (called seqhilo
in Hibernate):
uses a hi/lo algorithm to efficiently generate identifiers of type
long
, short
or
int
, given a named database sequence.
TABLE (called
MultipleHiLoPerTableGenerator
in Hibernate)
: uses a hi/lo algorithm to efficiently generate identifiers of
type long
, short
or
int
, given a table and column as a source of hi
values. The hi/lo algorithm generates identifiers that are unique
only for a particular database.
AUTO: selects IDENTITY
,
SEQUENCE
or TABLE
depending
upon the capabilities of the underlying database.
We recommend all new projects to use the new enhanced
identifier generators. They are deactivated by default for entities
using annotations but can be activated using
hibernate.id.new_generator_mappings=true
. These new
generators are more efficient and closer to the JPA 2 specification
semantic.
However they are not backward compatible with existing Hibernate based application (if a sequence or a table is used for id generation). See XXXXXXX ??? for more information on how to activate them.
To mark an id property as generated, use the
@GeneratedValue
annotation. You can specify the
strategy used (default to AUTO
) by setting
strategy
.
@Entity
public class Customer {
@Id @GeneratedValue
Integer getId() { ... };
}
@Entity
public class Invoice {
@Id @GeneratedValue(strategy=GenerationType.IDENTITY)
Integer getId() { ... };
}
SEQUENCE
and TABLE
require
additional configurations that you can set using
@SequenceGenerator
and
@TableGenerator
:
name
: name of the generator
table
/ sequenceName
:
name of the table or the sequence (defaulting respectively to
hibernate_sequences
and
hibernate_sequence
)
catalog
/
schema
:
initialValue
: the value from which the id
is to start generating
allocationSize
: the amount to increment
by when allocating id numbers from the generator
In addition, the TABLE
strategy also let
you customize:
pkColumnName
: the column name containing
the entity identifier
valueColumnName
: the column name
containing the identifier value
pkColumnValue
: the entity
identifier
uniqueConstraints
: any potential column
constraint on the table containing the ids
To link a table or sequence generator definition with an actual
generated property, use the same name in both the definition
name
and the generator value
generator
as shown below.
@Id
@GeneratedValue(
strategy=GenerationType.SEQUENCE,
generator="SEQ_GEN")
@javax.persistence.SequenceGenerator(
name="SEQ_GEN",
sequenceName="my_sequence",
allocationSize=20
)
public Integer getId() { ... }
The scope of a generator definition 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 in JPA's XML deployment descriptors (see XXXXXX ???):
<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 a JPA XML descriptor (like
META-INF/orm.xml
) is used to define the
generators, EMP_GEN
and SEQ_GEN
are application level generators.
Package level definition is not supported by the JPA
specification. However, you can use the
@GenericGenerator
at the package level (see ???).
These are the four standard JPA generators. Hibernate goes
beyond that and provide additional generators or additional options as
we will see below. You can also write your own custom identifier
generator by implementing
org.hibernate.id.IdentifierGenerator
.
To define a custom generator, use the
@GenericGenerator
annotation (and its plural
counter part @GenericGenerators
) that describes
the class of the identifier generator or its short cut name (as
described below) and a list of key/value parameters. When using
@GenericGenerator
and assigning it via
@GeneratedValue.generator
, the
@GeneratedValue.strategy
is ignored: leave it
blank.
@Id @GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
public String getId() {
@Id @GeneratedValue(generator="trigger-generated")
@GenericGenerator(
name="trigger-generated",
strategy = "select",
parameters = @Parameter(name="key", value = "socialSecurityNumber")
)
public String getId() {
The hbm.xml approach uses the optional
<generator>
child element inside
<id>
. If any parameters are required to
configure or initialize the generator instance, they are passed using
the <param>
element.
<id name="id" type="long" column="cat_id">
<generator class="org.hibernate.id.TableHiLoGenerator">
<param name="table">uid_table</param>
<param name="column">next_hi_value_column</param>
</generator>
</id>
All generators implement the interface
org.hibernate.id.IdentifierGenerator
. This is a
very simple interface. Some applications can choose to provide their
own specialized implementations, however, Hibernate provides a range
of built-in implementations. The shortcut names for the built-in
generators are as follows:
increment
generates identifiers of type long
,
short
or int
that are
unique only when no other process is inserting data into the
same table. Do not use in a
cluster.
identity
supports identity columns in DB2, MySQL, MS SQL
Server, Sybase and HypersonicSQL. The returned identifier is
of type long
, short
or
int
.
sequence
uses a sequence in DB2, PostgreSQL, Oracle, SAP DB,
McKoi or a generator in Interbase. The returned identifier
is of type long
, short
or int
hilo
uses a hi/lo algorithm to efficiently generate
identifiers of type long
,
short
or int
, given a
table and column (by default
hibernate_unique_key
and
next_hi
respectively) as a source of hi
values. The hi/lo algorithm generates identifiers that are
unique only for a particular database.
seqhilo
uses a hi/lo algorithm to efficiently generate
identifiers of type long
,
short
or int
, given a
named database sequence.
uuid
Generates a 128-bit UUID based on a custom algorithm. The value generated is represented as a string of 32 hexidecimal digits. Users can also configure it to use a separator (config parameter "separator") which separates the hexidecimal digits into 8{sep}8{sep}4{sep}8{sep}4. Note specifically that this is different than the IETF RFC 4122 representation of 8-4-4-4-12. If you need RFC 4122 compliant UUIDs, consider using "uuid2" generator discussed below.
uuid2
Generates a IETF RFC 4122 compliant (variant 2)
128-bit UUID. The exact "version" (the RFC term) generated
depends on the pluggable "generation strategy" used (see
below). Capable of generating values as
java.util.UUID
,
java.lang.String
or as a byte array
of length 16 (byte[16]
). The "generation
strategy" is defined by the interface
org.hibernate.id.UUIDGenerationStrategy
.
The generator defines 2 configuration parameters for
defining which generation strategy to use:
uuid_gen_strategy_class
Names the UUIDGenerationStrategy class to use
uuid_gen_strategy
Names the UUIDGenerationStrategy instance to use
Out of the box, comes with the following strategies:
org.hibernate.id.uuid.StandardRandomStrategy
(the default) - generates "version 3" (aka, "random")
UUID values via the
randomUUID
method of
java.util.UUID
org.hibernate.id.uuid.CustomVersionOneStrategy
- generates "version 1" UUID values, using IP address
since mac address not available. If you need mac
address to be used, consider leveraging one of the
existing third party UUID generators which sniff out
mac address and integrating it via the
org.hibernate.id.UUIDGenerationStrategy
contract. Two such libraries known at time of this
writing include http://johannburkard.de/software/uuid/
and http://commons.apache.org/sandbox/id/uuid.html
guid
uses a database-generated GUID string on MS SQL Server and MySQL.
native
selects identity
,
sequence
or hilo
depending upon the capabilities of the underlying
database.
assigned
lets the application assign an identifier to the
object before save()
is called. This is
the default strategy if no
<generator>
element is
specified.
select
retrieves a primary key, assigned by a database trigger, by selecting the row by some unique key and retrieving the primary key value.
foreign
uses the identifier of another associated object. It
is usually used in conjunction with a
<one-to-one>
primary key
association.
sequence-identity
a specialized sequence generation strategy that utilizes a database sequence for the actual value generation, but combines this with JDBC3 getGeneratedKeys to return the generated identifier value as part of the insert statement execution. This strategy is only supported on Oracle 10g drivers targeted for JDK 1.4. Comments on these insert statements are disabled due to a bug in the Oracle drivers.
The hilo
and seqhilo
generators provide two alternate implementations of the hi/lo
algorithm. The first implementation requires a "special" database
table to hold the next available "hi" value. Where supported, the
second uses an Oracle-style sequence.
<id name="id" type="long" column="cat_id">
<generator class="hilo">
<param name="table">hi_value</param>
<param name="column">next_value</param>
<param name="max_lo">100</param>
</generator>
</id>
<id name="id" type="long" column="cat_id">
<generator class="seqhilo">
<param name="sequence">hi_value</param>
<param name="max_lo">100</param>
</generator>
</id>
Unfortunately, you cannot use hilo
when
supplying your own Connection
to Hibernate. When
Hibernate uses an application server datasource to obtain
connections enlisted with JTA, you must configure the
hibernate.transaction.manager_lookup_class
.
The UUID contains: IP address, startup time of the JVM that is accurate to a quarter second, system time and a counter value that is unique within the JVM. It is not possible to obtain a MAC address or memory address from Java code, so this is the best option without using JNI.
For databases that support identity columns (DB2, MySQL,
Sybase, MS SQL), you can use identity
key
generation. For databases that support sequences (DB2, Oracle,
PostgreSQL, Interbase, McKoi, SAP DB) you can use
sequence
style key generation. Both of these
strategies require two SQL queries to insert a new object. For
example:
<id name="id" type="long" column="person_id">
<generator class="sequence">
<param name="sequence">person_id_sequence</param>
</generator>
</id>
<id name="id" type="long" column="person_id" unsaved-value="0">
<generator class="identity"/>
</id>
For cross-platform development, the native
strategy will, depending on the capabilities of the underlying
database, choose from the identity
,
sequence
and hilo
strategies.
If you want the application to assign identifiers, as opposed
to having Hibernate generate them, you can use the
assigned
generator. This special generator uses
the identifier value already assigned to the object's identifier
property. The generator is used when the primary key is a natural
key instead of a surrogate key. This is the default behavior if you
do not specify @GeneratedValue
nor
<generator>
elements.
The assigned
generator makes Hibernate use
unsaved-value="undefined"
. This forces Hibernate
to go to the database to determine if an instance is transient or
detached, unless there is a version or timestamp property, or you
define Interceptor.isUnsaved()
.
Hibernate does not generate DDL with triggers. It is for legacy schemas only.
<id name="id" type="long" column="person_id">
<generator class="select">
<param name="key">socialSecurityNumber</param>
</generator>
</id>
In the above example, there is a unique valued property named
socialSecurityNumber
. It is defined by the class,
as a natural key and a surrogate key named
person_id
, whose value is generated by a
trigger.
Finally, you can ask Hibernate to copy the identifier from another associated entity. In the Hibernate jargon, it is known as a foreign generator but the JPA mapping reads better and is encouraged.
@Entity
class MedicalHistory implements Serializable {
@Id @OneToOne
@JoinColumn(name = "person_id")
Person patient;
}
@Entity
public class Person implements Serializable {
@Id @GeneratedValue Integer id;
}
Or alternatively
@Entity
class MedicalHistory implements Serializable {
@Id Integer id;
@MapsId @OneToOne
@JoinColumn(name = "patient_id")
Person patient;
}
@Entity
class Person {
@Id @GeneratedValue Integer id;
}
In hbm.xml use the following approach:
<class name="MedicalHistory">
<id name="id">
<generator class="foreign">
<param name="property">patient</param>
</generator>
</id>
<one-to-one name="patient" class="Person" constrained="true"/>
</class>
Starting with release 3.2.3, there are 2 new generators which represent a re-thinking of 2 different aspects of identifier generation. The first aspect is database portability; the second is optimization Optimization means that you do not have to query the database for every request for a new identifier value. These two new generators are intended to take the place of some of the named generators described above, starting in 3.3.x. However, they are included in the current releases and can be referenced by FQN.
The first of these new generators is
org.hibernate.id.enhanced.SequenceStyleGenerator
which is intended, firstly, as a replacement for the
sequence
generator and, secondly, as a better
portability generator than native
. This is because
native
generally chooses between
identity
and sequence
which have
largely different semantics that can cause subtle issues in
applications eyeing portability.
org.hibernate.id.enhanced.SequenceStyleGenerator
,
however, achieves portability in a different manner. It chooses
between a table or a sequence in the database to store its
incrementing values, depending on the capabilities of the dialect
being used. The difference between this and native
is that table-based and sequence-based storage have the same exact
semantic. In fact, sequences are exactly what Hibernate tries to
emulate with its table-based generators. This generator has a number
of configuration parameters:
sequence_name
(optional, defaults to
hibernate_sequence
): the name of the sequence
or table to be used.
initial_value
(optional, defaults to
1
): the initial value to be retrieved from
the sequence/table. In sequence creation terms, this is
analogous to the clause typically named "STARTS WITH".
increment_size
(optional - defaults to
1
): the value by which subsequent calls to
the sequence/table should differ. In sequence creation terms,
this is analogous to the clause typically named "INCREMENT
BY".
force_table_use
(optional - defaults to
false
): should we force the use of a table as
the backing structure even though the dialect might support
sequence?
value_column
(optional - defaults to
next_val
): only relevant for table
structures, it is the name of the column on the table which is
used to hold the value.
optimizer
(optional - defaults to
none
): See Section 5.1.2.3.1, “Identifier generator optimization”
The second of these new generators is
org.hibernate.id.enhanced.TableGenerator
, which is
intended, firstly, as a replacement for the table
generator, even though it actually functions much more like
org.hibernate.id.MultipleHiLoPerTableGenerator
, and
secondly, as a re-implementation of
org.hibernate.id.MultipleHiLoPerTableGenerator
that
utilizes the notion of pluggable optimizers. Essentially this
generator defines a table capable of holding a number of different
increment values simultaneously by using multiple distinctly keyed
rows. This generator has a number of configuration parameters:
table_name
(optional - defaults to
hibernate_sequences
): the name of the table
to be used.
value_column_name
(optional - defaults
to next_val
): the name of the column on the
table that is used to hold the value.
segment_column_name
(optional -
defaults to sequence_name
): the name of the
column on the table that is used to hold the "segment key". This
is the value which identifies which increment value to
use.
segment_value
(optional - defaults to
default
): The "segment key" value for the
segment from which we want to pull increment values for this
generator.
segment_value_length
(optional -
defaults to 255
): Used for schema generation;
the column size to create this segment key column.
initial_value
(optional - defaults to
1
): The initial value to be retrieved from
the table.
increment_size
(optional - defaults to
1
): The value by which subsequent calls to
the table should differ.
optimizer
(optional - defaults to
??
): See Section 5.1.2.3.1, “Identifier generator optimization”.
For identifier generators that store values in the database, it is inefficient for them to hit the database on each and every call to generate a new identifier value. Instead, you can group a bunch of them in memory and only hit the database when you have exhausted your in-memory value group. This is the role of the pluggable optimizers. Currently only the two enhanced generators (Section 5.1.2.3, “Enhanced identifier generators” support this operation.
none
(generally this is the default if
no optimizer was specified): this will not perform any
optimizations and hit the database for each and every
request.
hilo
: applies a hi/lo algorithm around
the database retrieved values. The values from the database for
this optimizer are expected to be sequential. The values
retrieved from the database structure for this optimizer
indicates the "group number". The
increment_size
is multiplied by that value in
memory to define a group "hi value".
pooled
: as with the case of
hilo
, this optimizer attempts to minimize the
number of hits to the database. Here, however, we simply store
the starting value for the "next group" into the database
structure rather than a sequential value in combination with an
in-memory grouping algorithm. Here,
increment_size
refers to the values coming
from the database.
Hibernate supports the automatic generation of some of the
identifier properties. Simply use the
@GeneratedValue
annotation on one or several id
properties.
The Hibernate team has always felt such a construct as fundamentally wrong. Try hard to fix your data model before using this feature.
@Entity
public class CustomerInventory implements Serializable {
@Id
@TableGenerator(name = "inventory",
table = "U_SEQUENCES",
pkColumnName = "S_ID",
valueColumnName = "S_NEXTNUM",
pkColumnValue = "inventory",
allocationSize = 1000)
@GeneratedValue(strategy = GenerationType.TABLE, generator = "inventory")
Integer id;
@Id @ManyToOne(cascade = CascadeType.MERGE)
Customer customer;
}
@Entity
public class Customer implements Serializable {
@Id
private int id;
}
You can also generate properties inside an
@EmbeddedId
class.
When using long transactions or conversations that span several database transactions, it is useful to store versioning data to ensure that if the same entity is updated by two conversations, the last to commit changes will be informed and not override the other conversation's work. It guarantees some isolation while still allowing for good scalability and works particularly well in read-often write-sometimes situations.
You can use two approaches: a dedicated version number or a timestamp.
A version or timestamp property should never be null for a
detached instance. Hibernate will detect any instance with a null
version or timestamp as transient, irrespective of what other
unsaved-value
strategies are specified.
Declaring a nullable version or timestamp property is an easy
way to avoid problems with transitive reattachment in Hibernate. It is
especially useful for people using assigned identifiers or composite
keys.
You can add optimistic locking capability to an entity using the
@Version
annotation:
@Entity
public class Flight implements Serializable {
...
@Version
@Column(name="OPTLOCK")
public Integer getVersion() { ... }
}
The version property will be mapped to the
OPTLOCK
column, and the entity manager will use it
to detect conflicting updates (preventing lost updates you might
otherwise see with the last-commit-wins strategy).
The version column may be a numeric. Hibernate supports any kind
of type provided that you define and implement the appropriate
UserVersionType
.
The application must not alter the version number set up by
Hibernate in any way. To artificially increase the version number,
check in Hibernate Entity Manager's reference documentation
LockModeType.OPTIMISTIC_FORCE_INCREMENT
or
LockModeType.PESSIMISTIC_FORCE_INCREMENT
.
If the version number is generated by the database (via a
trigger for example), make sure to use
@org.hibernate.annotations.Generated(GenerationTime.ALWAYS).
To declare a version property in hbm.xml, use:
<version column="version_column" name="propertyName" type="typename" access="field|property|ClassName" unsaved-value="null|negative|undefined" generated="never|always" insert="true|false" node="element-name|@attribute-name|element/@attribute|." />
| |
| |
| |
| |
| |
| |
|
Alternatively, you can use a timestamp. Timestamps are a less safe implementation of optimistic locking. However, sometimes an application might use the timestamps in other ways as well.
Simply mark a property of type Date
or
Calendar
as
@Version
.
@Entity
public class Flight implements Serializable {
...
@Version
public Date getLastUpdate() { ... }
}
When using timestamp versioning you can tell Hibernate where to
retrieve the timestamp value from - database or JVM - by optionally
adding the @org.hibernate.annotations.Source
annotation to the property. Possible values for the value attribute of
the annotation are
org.hibernate.annotations.SourceType.VM
and
org.hibernate.annotations.SourceType.DB
. The
default is SourceType.DB
which is also used in
case there is no @Source
annotation at
all.
Like in the case of version numbers, the timestamp can also be
generated by the database instead of Hibernate. To do that, use
@org.hibernate.annotations.Generated(GenerationTime.ALWAYS).
In hbm.xml, use the <timestamp>
element:
<timestamp column="timestamp_column" name="propertyName" access="field|property|ClassName" unsaved-value="null|undefined" source="vm|db" generated="never|always" node="element-name|@attribute-name|element/@attribute|." />
| |
| |
| |
| |
| |
|
<Timestamp>
is equivalent to
<version type="timestamp">
. And
<timestamp source="db">
is equivalent to
<version type="dbtimestamp">
You need to decide which property needs to be made persistent in a given entity. This differs slightly between the annotation driven metadata and the hbm.xml files.
In the annotations world, every non static non transient
property (field or method depending on the access type) of an entity
is considered persistent, unless you annotate it as
@Transient
. Not having an annotation for your
property is equivalent to the appropriate @Basic
annotation.
The @Basic
annotation allows you to declare
the fetching strategy for a property. If set to
LAZY
, specifies that this property should be
fetched lazily when the instance variable is first accessed. It
requires build-time bytecode instrumentation, if your classes are not
instrumented, property level lazy loading is silently ignored. The
default is EAGER
. You can also mark a property as
not optional thanks to the @Basic.optional
attribute. This will ensure that the underlying column are not
nullable (if possible). Note that a better approach is to use the
@NotNull
annotation of the Bean Validation
specification.
Let's look at a few examples:
public transient int counter; //transient property
private String firstname; //persistent property
@Transient
String getLengthInMeter() { ... } //transient property
String getName() {... } // persistent property
@Basic
int getLength() { ... } // persistent property
@Basic(fetch = FetchType.LAZY)
String getDetailedComment() { ... } // persistent property
@Temporal(TemporalType.TIME)
java.util.Date getDepartureTime() { ... } // persistent property
@Enumerated(EnumType.STRING)
Starred getNote() { ... } //enum persisted as String in database
counter
, a transient field, and
lengthInMeter
, a method annotated as
@Transient
, and will be ignored by the Hibernate.
name
, length
, and
firstname
properties are mapped persistent and
eagerly fetched (the default for simple properties). The
detailedComment
property value will be lazily
fetched from the database once a lazy property of the entity is
accessed for the first time. Usually you don't need to lazy simple
properties (not to be confused with lazy association fetching). The
recommended alternative is to use the projection capability of JP-QL
(Java Persistence Query Language) or Criteria queries.
JPA support property mapping of all basic types supported by
Hibernate (all basic Java types , their respective wrappers and
serializable classes). Hibernate Annotations supports out of the box
enum type mapping either into a ordinal column (saving the enum
ordinal) or a string based column (saving the enum string
representation): the persistence representation, defaulted to ordinal,
can be overridden through the @Enumerated
annotation as shown in the note
property
example.
In plain Java APIs, the temporal precision of time is not
defined. When dealing with temporal data you might want to describe
the expected precision in database. Temporal data can have
DATE
, TIME
, or
TIMESTAMP
precision (ie the actual date, only the
time, or both). Use the @Temporal
annotation to
fine tune that.
@Lob
indicates that the property should be
persisted in a Blob or a Clob depending on the property type:
java.sql.Clob
,
Character[]
, char[]
and
java.lang.String
will be persisted in a Clob.
java.sql.Blob
, Byte[]
,
byte[]
and Serializable
type will be persisted in a Blob.
@Lob
public String getFullText() {
return fullText;
}
@Lob
public byte[] getFullCode() {
return fullCode;
}
If the property type implements
java.io.Serializable
and is not a basic type,
and if the property is not annotated with @Lob
,
then the Hibernate serializable
type is
used.
You can also manually specify a type using the
@org.hibernate.annotations.Type
and some
parameters if needed. @Type.type
could
be:
The name of a Hibernate basic type: integer,
string, character, date, timestamp, float, binary, serializable,
object, blob
etc.
The name of a Java class with a default basic type:
int, float, char, java.lang.String, java.util.Date,
java.lang.Integer, java.sql.Clob
etc.
The name of a serializable Java class.
The class name of a custom type:
com.illflow.type.MyCustomType
etc.
If you do not specify a type, Hibernate will use reflection upon the named property and guess the correct Hibernate type. Hibernate will attempt to interpret the name of the return class of the property getter using, in order, rules 2, 3, and 4.
@org.hibernate.annotations.TypeDef
and
@org.hibernate.annotations.TypeDefs
allows you to
declare type definitions. These annotations can be placed at the
class or package level. Note that these definitions are global for
the session factory (even when defined at the class level). If the
type is used on a single entity, you can place the definition on the
entity itself. Otherwise, it is recommended to place the definition
at the package level. In the example below, when Hibernate
encounters a property of class PhoneNumer
, it
delegates the persistence strategy to the custom mapping type
PhoneNumberType
. However, properties belonging to
other classes, too, can delegate their persistence strategy to
PhoneNumberType
, by explicitly using the
@Type
annotation.
Package level annotations are placed in a file named
package-info.java
in the appropriate package.
Place your annotations before the package declaration.
@TypeDef(
name = "phoneNumber",
defaultForType = PhoneNumber.class,
typeClass = PhoneNumberType.class
)
@Entity
public class ContactDetails {
[...]
private PhoneNumber localPhoneNumber;
@Type(type="phoneNumber")
private OverseasPhoneNumber overseasPhoneNumber;
[...]
}
The following example shows the usage of the
parameters
attribute to customize the
TypeDef.
//in org/hibernate/test/annotations/entity/package-info.java
@TypeDefs(
{
@TypeDef(
name="caster",
typeClass = CasterStringType.class,
parameters = {
@Parameter(name="cast", value="lower")
}
)
}
)
package org.hibernate.test.annotations.entity;
//in org/hibernate/test/annotations/entity/Forest.java
public class Forest {
@Type(type="caster")
public String getSmallText() {
...
}
When using composite user type, you will have to express
column definitions. The @Columns
has been
introduced for that purpose.
@Type(type="org.hibernate.test.annotations.entity.MonetaryAmountUserType")
@Columns(columns = {
@Column(name="r_amount"),
@Column(name="r_currency")
})
public MonetaryAmount getAmount() {
return amount;
}
public class MonetaryAmount implements Serializable {
private BigDecimal amount;
private Currency currency;
...
}
By default the access type of a class hierarchy is defined by
the position of the @Id
or
@EmbeddedId
annotations. If these annotations
are on a field, then only fields are considered for persistence and
the state is accessed via the field. If there annotations are on a
getter, then only the getters are considered for persistence and the
state is accessed via the getter/setter. That works well in practice
and is the recommended approach.
The placement of annotations within a class hierarchy has to be consistent (either field or on property) to be able to determine the default access type. It is recommended to stick to one single annotation placement strategy throughout your whole application.
However in some situations, you need to:
force the access type of the entity hierarchy
override the access type of a specific entity in the class hierarchy
override the access type of an embeddable type
The best use case is an embeddable class used by several entities that might not use the same access type. In this case it is better to force the access type at the embeddable class level.
To force the access type on a given class, use the
@Access
annotation as showed below:
@Entity
public class Order {
@Id private Long id;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
@Embedded private Address address;
public Address getAddress() { return address; }
public void setAddress() { this.address = address; }
}
@Entity
public class User {
private Long id;
@Id public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
private Address address;
@Embedded public Address getAddress() { return address; }
public void setAddress() { this.address = address; }
}
@Embeddable
@Access(AcessType.PROPERTY)
public class Address {
private String street1;
public String getStreet1() { return street1; }
public void setStreet1() { this.street1 = street1; }
private hashCode; //not persistent
}
You can also override the access type of a single property while keeping the other properties standard.
@Entity
public class Order {
@Id private Long id;
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
@Transient private String userId;
@Transient private String orderId;
@Access(AccessType.PROPERTY)
public String getOrderNumber() { return userId + ":" + orderId; }
public void setOrderNumber() { this.userId = ...; this.orderId = ...; }
}
In this example, the default access type is
FIELD
except for the
orderNumber
property. Note that the corresponding
field, if any must be marked as @Transient
or
transient
.
The annotation
@org.hibernate.annotations.AccessType
should be considered deprecated for FIELD and PROPERTY access. It
is still useful however if you need to use a custom access
type.
It is sometimes useful to avoid increasing the version number
even if a given property is dirty (particularly collections). You
can do that by annotating the property (or collection) with
@OptimisticLock(excluded=true)
.
More formally, specifies that updates to this property do not require acquisition of the optimistic lock.
The column(s) used for a property mapping can be defined using
the @Column
annotation. Use it to override
default values (see the JPA specification for more information on
the defaults). You can use this annotation at the property level for
properties that are:
not annotated at all
annotated with @Basic
annotated with @Version
annotated with @Lob
annotated with @Temporal
@Entity
public class Flight implements Serializable {
...
@Column(updatable = false, name = "flight_name", nullable = false, length=50)
public String getName() { ... }
The name
property is mapped to the
flight_name
column, which is not nullable, has a
length of 50 and is not updatable (making the property
immutable).
This annotation can be applied to regular properties as well
as @Id
or @Version
properties.
@Column( name="columnName"; boolean unique() default false; boolean nullable() default true; boolean insertable() default true; boolean updatable() default true; String columnDefinition() default ""; String table() default ""; int length() default 255; int precision() default 0; // decimal precision int scale() default 0; // decimal scale
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
Sometimes, you want the Database to do some computation for you rather than in the JVM, you might also create some kind of virtual column. You can use a SQL fragment (aka formula) instead of mapping a property into a column. This kind of property is read only (its value is calculated by your formula fragment).
@Formula("obj_length * obj_height * obj_width")
public long getObjectVolume()
The SQL fragment can be as complex as you want and even include subselects.
If a property is not annotated, the following rules apply:
If the property is of a single type, it is mapped as @Basic
Otherwise, if the type of the property is annotated as @Embeddable, it is mapped as @Embedded
Otherwise, if the type of the property is
Serializable
, it is mapped as
@Basic
in a column holding the object
in its serialized version
Otherwise, if the type of the property is
java.sql.Clob
or
java.sql.Blob
, it is mapped as
@Lob
with the appropriate
LobType
The <property>
element declares a
persistent JavaBean style property of the class.
<property name="propertyName" column="column_name" type="typename" update="true|false" insert="true|false" formula="arbitrary SQL expression" access="field|property|ClassName" lazy="true|false" unique="true|false" not-null="true|false" optimistic-lock="true|false" generated="never|insert|always" node="element-name|@attribute-name|element/@attribute|." index="index_name" unique_key="unique_key_id" length="L" precision="P" scale="S" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
typename could be:
The name of a Hibernate basic type: integer,
string, character, date, timestamp, float, binary, serializable,
object, blob
etc.
The name of a Java class with a default basic type:
int, float, char, java.lang.String, java.util.Date,
java.lang.Integer, java.sql.Clob
etc.
The name of a serializable Java class.
The class name of a custom type:
com.illflow.type.MyCustomType
etc.
If you do not specify a type, Hibernate will use reflection upon
the named property and guess the correct Hibernate type. Hibernate
will attempt to interpret the name of the return class of the property
getter using, in order, rules 2, 3, and 4. In certain cases you will
need the type
attribute. For example, to
distinguish between Hibernate.DATE
and
Hibernate.TIMESTAMP
, or to specify a custom
type.
The access
attribute allows you to control
how Hibernate accesses the property at runtime. By default, Hibernate
will call the property get/set pair. If you specify
access="field"
, Hibernate will bypass the get/set
pair and access the field directly using reflection. You can specify
your own strategy for property access by naming a class that
implements the interface
org.hibernate.property.PropertyAccessor
.
A powerful feature is derived properties. These properties are
by definition read-only. The property value is computed at load time.
You declare the computation as an SQL expression. This then translates
to a SELECT
clause subquery in the SQL query that
loads an instance:
<property name="totalPrice"
formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p
WHERE li.productId = p.productId
AND li.customerId = customerId
AND li.orderNumber = orderNumber )"/>
You can reference the entity table by not declaring an alias on
a particular column. This would be customerId
in
the given example. You can also use the nested
<formula>
mapping element if you do not want
to use the attribute.
Embeddable objects (or components) are objects whose properties are mapped to the same table as the owning entity's table. Components can, in turn, declare their own properties, components or collections
It is possible to declare an embedded component inside an entity
and even override its column mapping. Component classes have to be
annotated at the class level with the @Embeddable
annotation. It is possible to override the column mapping of an embedded
object for a particular entity using the @Embedded
and @AttributeOverride
annotation in the associated
property:
@Entity
public class Person implements Serializable {
// Persistent component using defaults
Address homeAddress;
@Embedded
@AttributeOverrides( {
@AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
@AttributeOverride(name="name", column = @Column(name="bornCountryName") )
} )
Country bornIn;
...
}
@Embeddable
public class Address implements Serializable {
String city;
Country nationality; //no overriding here
}
@Embeddable
public class Country implements Serializable {
private String iso2;
@Column(name="countryName") private String name;
public String getIso2() { return iso2; }
public void setIso2(String iso2) { this.iso2 = iso2; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
...
}
An embeddable object inherits the access type of its owning entity
(note that you can override that using the @Access
annotation).
The Person
entity has two component properties,
homeAddress
and bornIn
.
homeAddress
property has not been annotated, but
Hibernate will guess that it is a persistent component by looking for
the @Embeddable
annotation in the Address class. We
also override the mapping of a column name (to
bornCountryName
) with the
@Embedded
and @AttributeOverride
annotations for each mapped attribute of
Country
. As you can see, Country
is also a nested component of Address
,
again using auto-detection by Hibernate and JPA defaults. Overriding
columns of embedded objects of embedded objects is through dotted
expressions.
@Embedded
@AttributeOverrides( {
@AttributeOverride(name="city", column = @Column(name="fld_city") ),
@AttributeOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ),
@AttributeOverride(name="nationality.name", column = @Column(name="nat_CountryName") )
//nationality columns in homeAddress are overridden
} )
Address homeAddress;
Hibernate Annotations supports something that is not explicitly
supported by the JPA specification. You can annotate a embedded object
with the @MappedSuperclass
annotation to make the
superclass properties persistent (see
@MappedSuperclass
for more informations).
You can also use association annotations in an embeddable object
(ie @OneToOne
, @ManyToOne
,
@OneToMany
or @ManyToMany
). To
override the association columns you can use
@AssociationOverride
.
If you want to have the same embeddable object type twice in the
same entity, the column name defaulting will not work as several
embedded objects would share the same set of columns. In plain JPA, you
need to override at least one set of columns. Hibernate, however, allows
you to enhance the default naming mechanism through the
NamingStrategy
interface. You can write a
strategy that prevent name clashing in such a situation.
DefaultComponentSafeNamingStrategy
is an example
of this.
If a property of the embedded object points back to the owning
entity, annotate it with the @Parent
annotation.
Hibernate will make sure this property is properly loaded with the
entity reference.
In XML, use the <component>
element.
<component name="propertyName" class="className" insert="true|false" update="true|false" access="field|property|ClassName" lazy="true|false" optimistic-lock="true|false" unique="true|false" node="element-name|." > <property ...../> <many-to-one .... /> ........ </component>
| |
| |
| |
| |
| |
| |
| |
|
The child <property>
tags map properties
of the child class to table columns.
The <component>
element allows a
<parent>
subelement that maps a property of the
component class as a reference back to the containing entity.
The <dynamic-component>
element allows a
Map
to be mapped as a component, where the property
names refer to keys of the map. See Section 9.5, “Dynamic components” for more information. This feature is
not supported in annotations.
Java is a language supporting polymorphism: a class can inherit from another. Several strategies are possible to persist a class hierarchy:
Single table per class hierarchy strategy: a single table hosts all the instances of a class hierarchy
Joined subclass strategy: one table per class and subclass is present and each table persist the properties specific to a given subclass. The state of the entity is then stored in its corresponding class table and all its superclasses
Table per class strategy: one table per concrete class and subclass is present and each table persist the properties of the class and its superclasses. The state of the entity is then stored entirely in the dedicated table for its class.
With this approach the properties of all the subclasses in a given mapped class hierarchy are stored in a single table.
Each subclass declares its own persistent properties and subclasses. Version and id properties are assumed to be inherited from the root class. Each subclass in a hierarchy must define a unique discriminator value. If this is not specified, the fully qualified Java class name is used.
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name="planetype",
discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue("Plane")
public class Plane { ... }
@Entity
@DiscriminatorValue("A320")
public class A320 extends Plane { ... }
In hbm.xml, for the table-per-class-hierarchy mapping strategy,
the <subclass>
declaration is used. For
example:
<subclass name="ClassName" discriminator-value="discriminator_value" proxy="ProxyInterface" lazy="true|false" dynamic-update="true|false" dynamic-insert="true|false" entity-name="EntityName" node="element-name" extends="SuperclassName"> <property .... /> ..... </subclass>
| |
| |
| |
|
For information about inheritance mappings see Chapter 10, Inheritance mapping.
Discriminators are required for polymorphic persistence using
the table-per-class-hierarchy mapping strategy. It declares a
discriminator column of the table. The discriminator column contains
marker values that tell the persistence layer what subclass to
instantiate for a particular row. Hibernate Core supports the
follwoing restricted set of types as discriminator column:
string
, character
,
integer
, byte
,
short
, boolean
,
yes_no
, true_false
.
Use the @DiscriminatorColumn
to define
the discriminator column as well as the discriminator type.
The enum DiscriminatorType
used in
javax.persitence.DiscriminatorColumn
only
contains the values STRING
,
CHAR
and INTEGER
which
means that not all Hibernate supported types are available via
the @DiscriminatorColumn
annotation.
You can also use
@DiscriminatorFormula
to express in SQL a
virtual discriminator column. This is particularly useful when the
discriminator value can be extracted from one or more columns of the
table. Both @DiscriminatorColumn
and
@DiscriminatorFormula
are to be set on the
root entity (once per persisted hierarchy).
@org.hibernate.annotations.DiscriminatorOptions
allows to optionally specify Hibernate specific discriminator
options which are not standardized in JPA. The available options are
force
and insert
. The
force
attribute is useful if the table contains
rows with "extra" discriminator values that are not mapped to a
persistent class. This could for example occur when working with a
legacy database. If force
is set to
true
Hibernate will specify the allowed
discriminator values in the SELECT
query, even
when retrieving all instances of the root class. The second option -
insert
- tells Hibernate whether or not to
include the discriminator column in SQL INSERTs
.
Usually the column should be part of the INSERT
statement, but if your discriminator column is also part of a mapped
composite identifier you have to set this option to
false
.
There is also a
@org.hibernate.annotations.ForceDiscriminator
annotation which is deprecated since version 3.6. Use
@DiscriminatorOptions
instead.
Finally, use @DiscriminatorValue
on
each class of the hierarchy to specify the value stored in the
discriminator column for a given entity. If you do not set
@DiscriminatorValue
on a class, the fully
qualified class name is used.
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name="planetype",
discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue("Plane")
public class Plane { ... }
@Entity
@DiscriminatorValue("A320")
public class A320 extends Plane { ... }
In hbm.xml, the <discriminator>
element is used to define the discriminator column or
formula:
<discriminator column="discriminator_column" type="discriminator_type" force="true|false" insert="true|false" formula="arbitrary sql expression" />
| |
| |
| |
| |
|
Actual values of the discriminator column are specified by the
discriminator-value
attribute of the
<class>
and
<subclass>
elements.
The formula
attribute allows you to declare
an arbitrary SQL expression that will be used to evaluate the type
of a row. For example:
<discriminator
formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"
type="integer"/>
Each subclass can also be mapped to its own table. This is
called the table-per-subclass mapping strategy. An inherited state is
retrieved by joining with the table of the superclass. A discriminator
column is not required for this mapping strategy. Each subclass must,
however, declare a table column holding the object identifier. The
primary key of this table is also a foreign key to the superclass
table and described by the
@PrimaryKeyJoinColumn
s or the
<key>
element.
@Entity @Table(name="CATS")
@Inheritance(strategy=InheritanceType.JOINED)
public class Cat implements Serializable {
@Id @GeneratedValue(generator="cat-uuid")
@GenericGenerator(name="cat-uuid", strategy="uuid")
String getId() { return id; }
...
}
@Entity @Table(name="DOMESTIC_CATS")
@PrimaryKeyJoinColumn(name="CAT")
public class DomesticCat extends Cat {
public String getName() { return name; }
}
The table name still defaults to the non qualified class name.
Also if @PrimaryKeyJoinColumn
is not set, the
primary key / foreign key columns are assumed to have the same names
as the primary key columns of the primary table of the
superclass.
In hbm.xml, use the <joined-subclass>
element. For example:
<joined-subclass name="ClassName" table="tablename" proxy="ProxyInterface" lazy="true|false" dynamic-update="true|false" dynamic-insert="true|false" schema="schema" catalog="catalog" extends="SuperclassName" persister="ClassName" subselect="SQL expression" entity-name="EntityName" node="element-name"> <key .... > <property .... /> ..... </joined-subclass>
| |
| |
| |
|
Use the <key>
element to declare the
primary key / foreign key column. The mapping at the start of the
chapter would then be re-written as:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD//EN"
"http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="eg">
<class name="Cat" table="CATS">
<id name="id" column="uid" type="long">
<generator class="hilo"/>
</id>
<property name="birthdate" type="date"/>
<property name="color" not-null="true"/>
<property name="sex" not-null="true"/>
<property name="weight"/>
<many-to-one name="mate"/>
<set name="kittens">
<key column="MOTHER"/>
<one-to-many class="Cat"/>
</set>
<joined-subclass name="DomesticCat" table="DOMESTIC_CATS">
<key column="CAT"/>
<property name="name" type="string"/>
</joined-subclass>
</class>
<class name="eg.Dog">
<!-- mapping for Dog could go here -->
</class>
</hibernate-mapping>
For information about inheritance mappings see Chapter 10, Inheritance mapping.
A third option is to map only the concrete classes of an inheritance hierarchy to tables. This is called the table-per-concrete-class strategy. Each table defines all persistent states of the class, including the inherited state. In Hibernate, it is not necessary to explicitly map such inheritance hierarchies. You can map each class as a separate entity root. However, if you wish use polymorphic associations (e.g. an association to the superclass of your hierarchy), you need to use the union subclass mapping.
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Flight implements Serializable { ... }
Or in hbm.xml:
<union-subclass name="ClassName" table="tablename" proxy="ProxyInterface" lazy="true|false" dynamic-update="true|false" dynamic-insert="true|false" schema="schema" catalog="catalog" extends="SuperclassName" abstract="true|false" persister="ClassName" subselect="SQL expression" entity-name="EntityName" node="element-name"> <property .... /> ..... </union-subclass>
| |
| |
| |
|
No discriminator column or key column is required for this mapping strategy.
For information about inheritance mappings see Chapter 10, Inheritance mapping.
This is sometimes useful to share common properties through a
technical or a business superclass without including it as a regular
mapped entity (ie no specific table for this entity). For that purpose
you can map them as @MappedSuperclass
.
@MappedSuperclass
public class BaseEntity {
@Basic
@Temporal(TemporalType.TIMESTAMP)
public Date getLastUpdate() { ... }
public String getLastUpdater() { ... }
...
}
@Entity class Order extends BaseEntity {
@Id public Integer getId() { ... }
...
}
In database, this hierarchy will be represented as an
Order
table having the id
,
lastUpdate
and lastUpdater
columns. The embedded superclass property mappings are copied into
their entity subclasses. Remember that the embeddable superclass is
not the root of the hierarchy though.
Properties from superclasses not mapped as
@MappedSuperclass
are ignored.
The default access type (field or methods) is used, unless you
use the @Access
annotation.
The same notion can be applied to
@Embeddable
objects to persist properties from
their superclasses. You also need to use
@MappedSuperclass
to do that (this should not be
considered as a standard EJB3 feature though)
It is allowed to mark a class as
@MappedSuperclass
in the middle of the mapped
inheritance hierarchy.
Any class in the hierarchy non annotated with
@MappedSuperclass
nor @Entity
will be ignored.
You can override columns defined in entity superclasses at the
root entity level using the @AttributeOverride
annotation.
@MappedSuperclass
public class FlyingObject implements Serializable {
public int getAltitude() {
return altitude;
}
@Transient
public int getMetricAltitude() {
return metricAltitude;
}
@ManyToOne
public PropulsionType getPropulsion() {
return metricAltitude;
}
...
}
@Entity
@AttributeOverride( name="altitude", column = @Column(name="fld_altitude") )
@AssociationOverride(
name="propulsion",
joinColumns = @JoinColumn(name="fld_propulsion_fk")
)
public class Plane extends FlyingObject {
...
}
The altitude
property will be persisted in an
fld_altitude
column of table
Plane
and the propulsion association will be
materialized in a fld_propulsion_fk
foreign key
column.
You can define @AttributeOverride
(s) and
@AssociationOverride
(s) on
@Entity
classes,
@MappedSuperclass
classes and properties pointing
to an @Embeddable
object.
In hbm.xml, simply map the properties of the superclass in the
<class>
element of the entity that needs to
inherit them.
While not recommended for a fresh schema, some legacy databases force your to map a single entity on several tables.
Using the @SecondaryTable
or
@SecondaryTables
class level annotations. To
express that a column is in a particular table, use the
table
parameter of @Column
or
@JoinColumn
.
@Entity
@Table(name="MainCat")
@SecondaryTables({
@SecondaryTable(name="Cat1", pkJoinColumns={
@PrimaryKeyJoinColumn(name="cat_id", referencedColumnName="id")
),
@SecondaryTable(name="Cat2", uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})})
})
public class Cat implements Serializable {
private Integer id;
private String name;
private String storyPart1;
private String storyPart2;
@Id @GeneratedValue
public Integer getId() {
return id;
}
public String getName() {
return name;
}
@Column(table="Cat1")
public String getStoryPart1() {
return storyPart1;
}
@Column(table="Cat2")
public String getStoryPart2() {
return storyPart2;
}
}
In this example, name
will be in
MainCat
. storyPart1
will be in
Cat1
and storyPart2
will be in
Cat2
. Cat1
will be joined to
MainCat
using the cat_id
as a
foreign key, and Cat2
using id
(ie the same column name, the MainCat
id column
has). Plus a unique constraint on storyPart2
has
been set.
There is also additional tuning accessible via the
@org.hibernate.annotations.Table
annotation:
fetch
: If set to JOIN, the default,
Hibernate will use an inner join to retrieve a secondary table
defined by a class or its superclasses and an outer join for a
secondary table defined by a subclass. If set to
SELECT
then Hibernate will use a sequential
select for a secondary table defined on a subclass, which will be
issued only if a row turns out to represent an instance of the
subclass. Inner joins will still be used to retrieve a secondary
defined by the class and its superclasses.
inverse
: If true, Hibernate will not try
to insert or update the properties defined by this join. Default
to false.
optional
: If enabled (the default),
Hibernate will insert a row only if the properties defined by this
join are non-null and will always use an outer join to retrieve
the properties.
foreignKey
: defines the Foreign Key name
of a secondary table pointing back to the primary table.
Make sure to use the secondary table name in the
appliesto
property
@Entity
@Table(name="MainCat")
@SecondaryTable(name="Cat1")
@org.hibernate.annotations.Table(
appliesTo="Cat1",
fetch=FetchMode.SELECT,
optional=true)
public class Cat implements Serializable {
private Integer id;
private String name;
private String storyPart1;
private String storyPart2;
@Id @GeneratedValue
public Integer getId() {
return id;
}
public String getName() {
return name;
}
@Column(table="Cat1")
public String getStoryPart1() {
return storyPart1;
}
@Column(table="Cat2")
public String getStoryPart2() {
return storyPart2;
}
}
In hbm.xml, use the <join>
element.
<join table="tablename" schema="owner" catalog="catalog" fetch="join|select" inverse="true|false" optional="true|false"> <key ... /> <property ... /> ... </join>
| |
| |
| |
| |
| |
|
For example, address information for a person can be mapped to a separate table while preserving value type semantics for all properties:
<class name="Person"
table="PERSON">
<id name="id" column="PERSON_ID">...</id>
<join table="ADDRESS">
<key column="ADDRESS_ID"/>
<property name="address"/>
<property name="zip"/>
<property name="country"/>
</join>
...
This feature is often only useful for legacy data models. We recommend fewer tables than classes and a fine-grained domain model. However, it is useful for switching between inheritance mapping strategies in a single hierarchy, as explained later.
To link one entity to an other, you need to map the association property as a to one association. In the relational model, you can either use a foreign key or an association table, or (a bit less common) share the same primary key value between the two entities.
To mark an association, use either
@ManyToOne
or
@OnetoOne
.
@ManyToOne
and @OneToOne
have a parameter named targetEntity
which describes
the target entity name. You usually don't need this parameter since the
default value (the type of the property that stores the association) is
good in almost all cases. However this is useful when you want to use
interfaces as the return type instead of the regular entity.
Setting a value of the cascade
attribute to any
meaningful value other than nothing will propagate certain operations to
the associated object. The meaningful values are divided into three
categories.
basic operations, which include: persist, merge,
delete, save-update, evict, replicate, lock and
refresh
;
special values: delete-orphan
or
all
;
comma-separated combinations of operation names:
cascade="persist,merge,evict"
or
cascade="all,delete-orphan"
. See Section 11.11, “Transitive persistence” for a full explanation. Note
that single valued many-to-one associations do not support orphan
delete.
By default, single point associations are eagerly fetched in JPA
2. You can mark it as lazily fetched by using
@ManyToOne(fetch=FetchType.LAZY)
in which case
Hibernate will proxy the association and load it when the state of the
associated entity is reached. You can force Hibernate not to use a proxy
by using @LazyToOne(NO_PROXY)
. In this case, the
property is fetched lazily when the instance variable is first accessed.
This requires build-time bytecode instrumentation. lazy="false"
specifies that the association will always be eagerly fetched.
With the default JPA options, single-ended associations are loaded
with a subsequent select if set to LAZY
, or a SQL
JOIN is used for EAGER
associations. You can however
adjust the fetching strategy, ie how data is fetched by using
@Fetch
. FetchMode
can be
SELECT
(a select is triggered when the association
needs to be loaded) or JOIN
(use a SQL JOIN to load
the association while loading the owner entity). JOIN
overrides any lazy attribute (an association loaded through a
JOIN
strategy cannot be lazy).
An ordinary association to another persistent class is declared using a
@ManyToOne
if several entities can
point to the the target entity
@OneToOne
if only a single entity can
point to the the target entity
and a foreign key in one table is referencing the primary key column(s) of the target table.
@Entity
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinColumn(name="COMP_ID")
public Company getCompany() {
return company;
}
...
}
The @JoinColumn
attribute is optional, the
default value(s) is the concatenation of the name of the relationship
in the owner side, _ (underscore), and the name of
the primary key column in the owned side. In this example
company_id
because the property name is
company
and the column id of Company is
id
.
@Entity
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=CompanyImpl.class )
@JoinColumn(name="COMP_ID")
public Company getCompany() {
return company;
}
...
}
public interface Company {
...
}
You can also map a to one association through an association
table. This association table described by the
@JoinTable
annotation will contains a foreign key
referencing back the entity table (through
@JoinTable.joinColumns
) and a a foreign key
referencing the target entity table (through
@JoinTable.inverseJoinColumns
).
@Entity
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinTable(name="Flight_Company",
joinColumns = @JoinColumn(name="FLIGHT_ID"),
inverseJoinColumns = @JoinColumn(name="COMP_ID")
)
public Company getCompany() {
return company;
}
...
}
You can use a SQL fragment to simulate a physical join column
using the @JoinColumnOrFormula
/
@JoinColumnOrformulas
annotations (just like
you can use a SQL fragment to simulate a property column via the
@Formula
annotation).
@Entity
public class Ticket implements Serializable {
@ManyToOne
@JoinColumnOrFormula(formula="(firstname + ' ' + lastname)")
public Person getOwner() {
return person;
}
...
}
You can mark an association as mandatory by using the
optional=false
attribute. We recommend to use Bean
Validation's @NotNull
annotation as a better
alternative however. As a consequence, the foreign key column(s) will
be marked as not nullable (if possible).
When Hibernate cannot resolve the association because the
expected associated element is not in database (wrong id on the
association column), an exception is raised. This might be
inconvenient for legacy and badly maintained schemas. You can ask
Hibernate to ignore such elements instead of raising an exception
using the @NotFound
annotation.
Example 5.1. @NotFound annotation
@Entity
public class Child {
...
@ManyToOne
@NotFound(action=NotFoundAction.IGNORE)
public Parent getParent() { ... }
...
}
Sometimes you want to delegate to your database the deletion of cascade when a given entity is deleted. In this case Hibernate generates a cascade delete constraint at the database level.
Example 5.2. @OnDelete annotation
@Entity
public class Child {
...
@ManyToOne
@OnDelete(action=OnDeleteAction.CASCADE)
public Parent getParent() { ... }
...
}
Foreign key constraints, while generated by Hibernate, have a
fairly unreadable name. You can override the constraint name using
@ForeignKey
.
Example 5.3. @ForeignKey annotation
@Entity
public class Child {
...
@ManyToOne
@ForeignKey(name="FK_PARENT")
public Parent getParent() { ... }
...
}
alter table Child add constraint FK_PARENT foreign key (parent_id) references Parent
Sometimes, you want to link one entity to an other not by the
target entity primary key but by a different unique key. You can
achieve that by referencing the unique key column(s) in
@JoinColumn.referenceColumnName
.
@Entity
class Person {
@Id Integer personNumber;
String firstName;
@Column(name="I")
String initial;
String lastName;
}
@Entity
class Home {
@ManyToOne
@JoinColumns({
@JoinColumn(name="first_name", referencedColumnName="firstName"),
@JoinColumn(name="init", referencedColumnName="I"),
@JoinColumn(name="last_name", referencedColumnName="lastName"),
})
Person owner
}
This is not encouraged however and should be reserved to legacy mappings.
In hbm.xml, mapping an association is similar. The main
difference is that a @OneToOne
is mapped as
<many-to-one unique="true"/>
, let's dive into
the subject.
<many-to-one name="propertyName" column="column_name" class="ClassName" cascade="cascade_style" fetch="join|select" update="true|false" insert="true|false" property-ref="propertyNameFromAssociatedClass" access="field|property|ClassName" unique="true|false" not-null="true|false" optimistic-lock="true|false" lazy="proxy|no-proxy|false" not-found="ignore|exception" entity-name="EntityName" formula="arbitrary SQL expression" node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" index="index_name" unique_key="unique_key_id" foreign-key="foreign_key_name" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
Setting a value of the cascade
attribute to
any meaningful value other than none
will propagate
certain operations to the associated object. The meaningful values are
divided into three categories. First, basic operations, which include:
persist, merge, delete, save-update, evict, replicate, lock
and refresh
; second, special values:
delete-orphan
; and third,all
comma-separated combinations of operation names:
cascade="persist,merge,evict"
or
cascade="all,delete-orphan"
. See Section 11.11, “Transitive persistence” for a full explanation. Note that
single valued, many-to-one and one-to-one, associations do not support
orphan delete.
Here is an example of a typical many-to-one
declaration:
<many-to-one name="product" class="Product" column="PRODUCT_ID"/>
The property-ref
attribute should only be
used for mapping legacy data where a foreign key refers to a unique
key of the associated table other than the primary key. This is a
complicated and confusing relational model. For example, if the
Product
class had a unique serial number that is
not the primary key. The unique
attribute controls
Hibernate's DDL generation with the SchemaExport tool.
<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>
Then the mapping for OrderItem
might
use:
<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>
This is not encouraged, however.
If the referenced unique key comprises multiple properties of
the associated entity, you should map the referenced properties inside
a named <properties>
element.
If the referenced unique key is the property of a component, you can specify a property path:
<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>
The second approach is to ensure an entity and its associated entity share the same primary key. In this case the primary key column is also a foreign key and there is no extra column. These associations are always one to one.
Example 5.4. One to One association
@Entity
public class Body {
@Id
public Long getId() { return id; }
@OneToOne(cascade = CascadeType.ALL)
@MapsId
public Heart getHeart() {
return heart;
}
...
}
@Entity
public class Heart {
@Id
public Long getId() { ...}
}
Many people got confused by these primary key based one to one
associations. They can only be lazily loaded if Hibernate knows that
the other side of the association is always present. To indicate to
Hibernate that it is the case, use
@OneToOne(optional=false)
.
In hbm.xml, use the following mapping.
<one-to-one name="propertyName" class="ClassName" cascade="cascade_style" constrained="true|false" fetch="join|select" property-ref="propertyNameFromAssociatedClass" access="field|property|ClassName" formula="any SQL expression" lazy="proxy|no-proxy|false" entity-name="EntityName" node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" foreign-key="foreign_key_name" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
Primary key associations do not need an extra table column. If two rows are related by the association, then the two table rows share the same primary key value. To relate two objects by a primary key association, ensure that they are assigned the same identifier value.
For a primary key association, add the following mappings to
Employee
and Person
respectively:
<one-to-one name="person" class="Person"/>
<one-to-one name="employee" class="Employee" constrained="true"/>
Ensure that the primary keys of the related rows in the PERSON
and EMPLOYEE tables are equal. You use a special Hibernate identifier
generation strategy called foreign
:
<class name="person" table="PERSON">
<id name="id" column="PERSON_ID">
<generator class="foreign">
<param name="property">employee</param>
</generator>
</id>
...
<one-to-one name="employee"
class="Employee"
constrained="true"/>
</class>
A newly saved instance of Person
is assigned
the same primary key value as the Employee
instance
referred with the employee
property of that
Person
.
Although we recommend the use of surrogate keys as primary keys,
you should try to identify natural keys for all entities. A natural key
is a property or combination of properties that is unique and non-null.
It is also immutable. Map the properties of the natural key as
@NaturalId
or map them inside the
<natural-id>
element. Hibernate will generate
the necessary unique key and nullability constraints and, as a result,
your mapping will be more self-documenting.
@Entity
public class Citizen {
@Id
@GeneratedValue
private Integer id;
private String firstname;
private String lastname;
@NaturalId
@ManyToOne
private State state;
@NaturalId
private String ssn;
...
}
//and later on query
List results = s.createCriteria( Citizen.class )
.add( Restrictions.naturalId().set( "ssn", "1234" ).set( "state", ste ) )
.list();
Or in XML,
<natural-id mutable="true|false"/>
<property ... />
<many-to-one ... />
......
</natural-id>
It is recommended that you implement equals()
and hashCode()
to compare the natural key properties
of the entity.
This mapping is not intended for use with entities that have natural primary keys.
mutable
(optional - defaults to
false
): by default, natural identifier properties
are assumed to be immutable (constant).
There is one more type of property mapping. The
@Any
mapping defines a polymorphic association to
classes from multiple tables. This type of mapping requires more than
one column. The first column contains the type of the associated entity.
The remaining columns contain the identifier. It is impossible to
specify a foreign key constraint for this kind of association. This is
not the usual way of mapping polymorphic associations and you should use
this only in special cases. For example, for audit logs, user session
data, etc.
The @Any
annotation describes the column
holding the metadata information. To link the value of the metadata
information and an actual entity type, The
@AnyDef
and @AnyDefs
annotations are used. The metaType
attribute allows
the application to specify a custom type that maps database column
values to persistent classes that have identifier properties of the type
specified by idType
. You must specify the mapping
from values of the metaType
to class names.
@Any( metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
@AnyMetaDef(
idType = "integer",
metaType = "string",
metaValues = {
@MetaValue( value = "S", targetEntity = StringProperty.class ),
@MetaValue( value = "I", targetEntity = IntegerProperty.class )
} )
@JoinColumn( name = "property_id" )
public Property getMainProperty() {
return mainProperty;
}
Note that @AnyDef
can be mutualized and
reused. It is recommended to place it as a package metadata in this
case.
//on a package
@AnyMetaDef( name="property"
idType = "integer",
metaType = "string",
metaValues = {
@MetaValue( value = "S", targetEntity = StringProperty.class ),
@MetaValue( value = "I", targetEntity = IntegerProperty.class )
} )
package org.hibernate.test.annotations.any;
//in a class
@Any( metaDef="property", metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER )
@JoinColumn( name = "property_id" )
public Property getMainProperty() {
return mainProperty;
}
The hbm.xml equivalent is:
<any name="being" id-type="long" meta-type="string">
<meta-value value="TBL_ANIMAL" class="Animal"/>
<meta-value value="TBL_HUMAN" class="Human"/>
<meta-value value="TBL_ALIEN" class="Alien"/>
<column name="table_name"/>
<column name="id"/>
</any>
You cannot mutualize the metadata in hbm.xml as you can in annotations.
<any name="propertyName" id-type="idtypename" meta-type="metatypename" cascade="cascade_style" access="field|property|ClassName" optimistic-lock="true|false" > <meta-value ... /> <meta-value ... /> ..... <column .... /> <column .... /> ..... </any>
| |
| |
| |
| |
| |
|
The <properties>
element allows the
definition of a named, logical grouping of the properties of a class.
The most important use of the construct is that it allows a combination
of properties to be the target of a property-ref
. It
is also a convenient way to define a multi-column unique constraint. For
example:
<properties name="logicalName" insert="true|false" update="true|false" optimistic-lock="true|false" unique="true|false" > <property ...../> <many-to-one .... /> ........ </properties>
| |
| |
| |
| |
|
For example, if we have the following
<properties>
mapping:
<class name="Person">
<id name="personNumber"/>
...
<properties name="name"
unique="true" update="false">
<property name="firstName"/>
<property name="initial"/>
<property name="lastName"/>
</properties>
</class>
You might have some legacy data association that refers to this
unique key of the Person
table, instead of to the
primary key:
<many-to-one name="owner"
class="Person" property-ref="name">
<column name="firstName"/>
<column name="initial"/>
<column name="lastName"/>
</many-to-one>
When using annotations as a mapping strategy, such construct is not necessary as the binding between a column and its related column on the associated table is done directly
@Entity
class Person {
@Id Integer personNumber;
String firstName;
@Column(name="I")
String initial;
String lastName;
}
@Entity
class Home {
@ManyToOne
@JoinColumns({
@JoinColumn(name="first_name", referencedColumnName="firstName"),
@JoinColumn(name="init", referencedColumnName="I"),
@JoinColumn(name="last_name", referencedColumnName="lastName"),
})
Person owner
}
The use of this outside the context of mapping legacy data is not recommended.
The hbm.xml structure has some specificities naturally not present when using annotations, let's describe them briefly.
All XML mappings should declare the doctype shown. The actual
DTD can be found at the URL above, in the directory
hibernate-x.x.x/src/org/hibernate
, or in
hibernate3.jar
. Hibernate will always look for the
DTD in its classpath first. If you experience lookups of the DTD using
an Internet connection, check the DTD declaration against the contents
of your classpath.
Hibernate will first attempt to resolve DTDs in its classpath.
It does this is by registering a custom
org.xml.sax.EntityResolver
implementation with
the SAXReader it uses to read in the xml files. This custom
EntityResolver
recognizes two different systemId
namespaces:
a hibernate namespace
is recognized
whenever the resolver encounters a systemId starting with
http://www.hibernate.org/dtd/
. The resolver
attempts to resolve these entities via the classloader which
loaded the Hibernate classes.
a user namespace
is recognized whenever
the resolver encounters a systemId using a
classpath://
URL protocol. The resolver will
attempt to resolve these entities via (1) the current thread
context classloader and (2) the classloader which loaded the
Hibernate classes.
The following is an example of utilizing user namespacing:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [
<!ENTITY types SYSTEM "classpath://your/domain/types.xml">
]>
<hibernate-mapping package="your.domain">
<class name="MyEntity">
<id name="id" type="my-custom-id-type">
...
</id>
<class>
&types;
</hibernate-mapping>
Where types.xml
is a resource in the
your.domain
package and contains a custom typedef.
This element has several optional attributes. The
schema
and catalog
attributes
specify that tables referred to in this mapping belong to the named
schema and/or catalog. If they are specified, tablenames will be
qualified by the given schema and catalog names. If they are missing,
tablenames will be unqualified. The default-cascade
attribute specifies what cascade style should be assumed for
properties and collections that do not specify a
cascade
attribute. By default, the
auto-import
attribute allows you to use unqualified
class names in the query language.
<hibernate-mapping schema="schemaName" catalog="catalogName" default-cascade="cascade_style" default-access="field|property|ClassName" default-lazy="true|false" auto-import="true|false" package="package.name" />
| |
| |
| |
| |
| |
| |
|
If you have two persistent classes with the same unqualified
name, you should set auto-import="false"
. An
exception will result if you attempt to assign two classes to the same
"imported" name.
The hibernate-mapping
element allows you to
nest several persistent <class>
mappings, as
shown above. It is, however, good practice (and expected by some
tools) to map only a single persistent class, or a single class
hierarchy, in one mapping file and name it after the persistent
superclass. For example, Cat.hbm.xml
,
Dog.hbm.xml
, or if using inheritance,
Animal.hbm.xml
.
The <key>
element is featured a few
times within this guide. It appears anywhere the parent mapping
element defines a join to a new table that references the primary key
of the original table. It also defines the foreign key in the joined
table:
<key column="columnname" on-delete="noaction|cascade" property-ref="propertyName" not-null="true|false" update="true|false" unique="true|false" />
| |
| |
| |
| |
| |
|
For systems where delete performance is important, we recommend
that all keys should be defined
on-delete="cascade"
. Hibernate uses a
database-level ON CASCADE DELETE
constraint,
instead of many individual DELETE
statements. Be
aware that this feature bypasses Hibernate's usual optimistic locking
strategy for versioned data.
The not-null
and update
attributes are useful when mapping a unidirectional one-to-many
association. If you map a unidirectional one-to-many association to a
non-nullable foreign key, you must declare the
key column using <key
not-null="true">
.
If your application has two persistent classes with the same
name, and you do not want to specify the fully qualified package name
in Hibernate queries, classes can be "imported" explicitly, rather
than relying upon auto-import="true"
. You can also
import classes and interfaces that are not explicitly mapped:
<import class="java.lang.Object" rename="Universe"/>
<import class="ClassName" rename="ShortName" />
| |
|
This feature is unique to hbm.xml and is not supported in annotations.
Mapping elements which accept a column
attribute will alternatively accept a
<column>
subelement. Likewise,
<formula>
is an alternative to the
formula
attribute. For example:
<column
name="column_name"
length="N"
precision="N"
scale="N"
not-null="true|false"
unique="true|false"
unique-key="multicolumn_unique_key_name"
index="index_name"
sql-type="sql_type_name"
check="SQL expression"
default="SQL expression"
read="SQL expression"
write="SQL expression"/>
<formula>SQL expression</formula>
Most of the attributes on column
provide a
means of tailoring the DDL during automatic schema generation. The
read
and write
attributes allow
you to specify custom SQL that Hibernate will use to access the
column's value. For more on this, see the discussion of column read and write
expressions.
The column
and formula
elements can even be combined within the same property or association
mapping to express, for example, exotic join conditions.
<many-to-one name="homeAddress" class="Address"
insert="false" update="false">
<column name="person_id" not-null="true" length="10"/>
<formula>'MAILING'</formula>
</many-to-one>
In relation to the persistence service, Java language-level objects are classified into two groups:
An entity exists independently of any other objects holding references to the entity. Contrast this with the usual Java model, where an unreferenced object is garbage collected. Entities must be explicitly saved and deleted. Saves and deletions, however, can be cascaded from a parent entity to its children. This is different from the ODMG model of object persistence by reachability and corresponds more closely to how application objects are usually used in large systems. Entities support circular and shared references. They can also be versioned.
An entity's persistent state consists of references to other entities and instances of value types. Values are primitives: collections (not what is inside a collection), components and certain immutable objects. Unlike entities, values in particular collections and components, are persisted and deleted by reachability. Since value objects and primitives are persisted and deleted along with their containing entity, they cannot be independently versioned. Values have no independent identity, so they cannot be shared by two entities or collections.
Until now, we have been using the term "persistent class" to refer
to entities. We will continue to do that. Not all user-defined classes
with a persistent state, however, are entities. A
component is a user-defined class with value
semantics. A Java property of type java.lang.String
also has value semantics. Given this definition, all types (classes)
provided by the JDK have value type semantics in Java, while
user-defined types can be mapped with entity or value type semantics.
This decision is up to the application developer. An entity class in a
domain model will normally have shared references to a single instance
of that class, while composition or aggregation usually translates to a
value type.
We will revisit both concepts throughout this reference guide.
The challenge is to map the Java type system, and the developers'
definition of entities and value types, to the SQL/database type system.
The bridge between both systems is provided by Hibernate. For entities,
<class>
, <subclass>
and so on are used. For value types we use
<property>
,
<component>
etc., that usually have a
type
attribute. The value of this attribute is the
name of a Hibernate mapping type. Hibernate
provides a range of mappings for standard JDK value types out of the
box. You can write your own mapping types and implement your own custom
conversion strategies.
With the exception of collections, all built-in Hibernate types support null semantics.
The built-in basic mapping types can be roughly categorized into the following:
integer, long, short, float, double, character,
byte, boolean, yes_no, true_false
Type mappings from Java primitives or wrapper classes to
appropriate (vendor-specific) SQL column types.
boolean, yes_no
and
true_false
are all alternative encodings for
a Java boolean
or
java.lang.Boolean
.
string
A type mapping from java.lang.String
to
VARCHAR
(or Oracle
VARCHAR2
).
date, time, timestamp
Type mappings from java.util.Date
and
its subclasses to SQL types DATE
,
TIME
and TIMESTAMP
(or
equivalent).
calendar, calendar_date
Type mappings from java.util.Calendar
to SQL types TIMESTAMP
and
DATE
(or equivalent).
big_decimal, big_integer
Type mappings from java.math.BigDecimal
and java.math.BigInteger
to
NUMERIC
(or Oracle
NUMBER
).
locale, timezone, currency
Type mappings from java.util.Locale
,
java.util.TimeZone
and
java.util.Currency
to
VARCHAR
(or Oracle
VARCHAR2
). Instances of
Locale
and Currency
are
mapped to their ISO codes. Instances of
TimeZone
are mapped to their
ID
.
class
A type mapping from java.lang.Class
to
VARCHAR
(or Oracle
VARCHAR2
). A Class
is
mapped to its fully qualified name.
binary
Maps byte arrays to an appropriate SQL binary type.
text
Maps long Java strings to a SQL LONGVARCHAR
or
TEXT
type.
image
Maps long byte arrays to a SQL LONGVARBINARY
.
serializable
Maps serializable Java types to an appropriate SQL binary
type. You can also indicate the Hibernate type
serializable
with the name of a serializable
Java class or interface that does not default to a basic
type.
clob, blob
Type mappings for the JDBC classes
java.sql.Clob
and
java.sql.Blob
. These types can be
inconvenient for some applications, since the blob or clob
object cannot be reused outside of a transaction. Driver support
is patchy and inconsistent.
materialized_clob
Maps long Java strings to a SQL CLOB
type. When read, the CLOB
value is
immediately materialized into a Java string. Some drivers
require the CLOB
value to be read within
a transaction. Once materialized, the Java string is
available outside of the transaction.
materialized_blob
Maps long Java byte arrays to a SQL BLOB
type. When read, the BLOB
value is
immediately materialized into a byte array. Some drivers
require the BLOB
value to be read within
a transaction. Once materialized, the byte array is
available outside of the transaction.
imm_date, imm_time, imm_timestamp, imm_calendar,
imm_calendar_date, imm_serializable, imm_binary
Type mappings for what are considered mutable Java types.
This is where Hibernate makes certain optimizations appropriate
only for immutable Java types, and the application treats the
object as immutable. For example, you should not call
Date.setTime()
for an instance mapped as
imm_timestamp
. To change the value of the
property, and have that change made persistent, the application
must assign a new, nonidentical, object to the property.
Unique identifiers of entities and collections can be of any basic
type except binary
, blob
and
clob
. Composite identifiers are also allowed. See
below for more information.
The basic value types have corresponding Type
constants defined on org.hibernate.Hibernate
. For
example, Hibernate.STRING
represents the
string
type.
It is relatively easy for developers to create their own value
types. For example, you might want to persist properties of type
java.lang.BigInteger
to VARCHAR
columns. Hibernate does not provide a built-in type for this. Custom
types are not limited to mapping a property, or collection element, to a
single table column. So, for example, you might have a Java property
getName()
/setName()
of type
java.lang.String
that is persisted to the columns
FIRST_NAME
, INITIAL
,
SURNAME
.
To implement a custom type, implement either
org.hibernate.UserType
or
org.hibernate.CompositeUserType
and declare
properties using the fully qualified classname of the type. View
org.hibernate.test.DoubleStringType
to see the kind
of things that are possible.
<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
<column name="first_string"/>
<column name="second_string"/>
</property>
Notice the use of <column>
tags to map a
property to multiple columns.
The CompositeUserType
,
EnhancedUserType
,
UserCollectionType
, and
UserVersionType
interfaces provide support for more
specialized uses.
You can even supply parameters to a UserType
in
the mapping file. To do this, your UserType
must
implement the
org.hibernate.usertype.ParameterizedType
interface.
To supply parameters to your custom type, you can use the
<type>
element in your mapping files.
<property name="priority">
<type name="com.mycompany.usertypes.DefaultValueIntegerType">
<param name="default">0</param>
</type>
</property>
The UserType
can now retrieve the value for the
parameter named default
from the
Properties
object passed to it.
If you regularly use a certain UserType
, it is
useful to define a shorter name for it. You can do this using the
<typedef>
element. Typedefs assign a name to a
custom type, and can also contain a list of default parameter values if
the type is parameterized.
<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
<param name="default">0</param>
</typedef>
<property name="priority" type="default_zero"/>
It is also possible to override the parameters supplied in a typedef on a case-by-case basis by using type parameters on the property mapping.
Even though Hibernate's rich range of built-in types and support
for components means you will rarely need to use a custom type, it is
considered good practice to use custom types for non-entity classes that
occur frequently in your application. For example, a
MonetaryAmount
class is a good candidate for a
CompositeUserType
, even though it could be mapped as
a component. One reason for this is abstraction. With a custom type,
your mapping documents would be protected against changes to the way
monetary values are represented.
It is possible to provide more than one mapping for a particular persistent class. In this case, you must specify an entity name to disambiguate between instances of the two mapped entities. By default, the entity name is the same as the class name. Hibernate lets you specify the entity name when working with persistent objects, when writing queries, or when mapping associations to the named entity.
<class name="Contract" table="Contracts" entity-name="CurrentContract"> ... <set name="history" inverse="true" order-by="effectiveEndDate desc"> <key column="currentContractId"/> <one-to-many entity-name="HistoricalContract"/> </set> </class> <class name="Contract" table="ContractHistory" entity-name="HistoricalContract"> ... <many-to-one name="currentContract" column="currentContractId" entity-name="CurrentContract"/> </class>
Associations are now specified using entity-name
instead of class
.
This feature is not supported in Annotations
You can force Hibernate to quote an identifier in the generated SQL
by enclosing the table or column name in backticks in the mapping
document. Hibernate will use the correct quotation style for the SQL
Dialect
. This is usually double quotes, but the SQL
Server uses brackets and MySQL uses backticks.
@Entity @Table(name="`Line Item`")
class LineItem {
@id @Column(name="`Item Id`") Integer id;
@Column(name="`Item #`") int itemNumber
}
<class name="LineItem" table="`Line Item`">
<id name="id" column="`Item Id`"/><generator class="assigned"/></id>
<property name="itemNumber" column="`Item #`"/>
...
</class>
Generated properties are properties that have their values generated
by the database. Typically, Hibernate applications needed to
refresh
objects that contain any properties for which
the database was generating values. Marking properties as generated,
however, lets the application delegate this responsibility to Hibernate.
When Hibernate issues an SQL INSERT or UPDATE for an entity that has
defined generated properties, it immediately issues a select afterwards to
retrieve the generated values.
Properties marked as generated must additionally be non-insertable and non-updateable. Only versions, timestamps, and simple properties, can be marked as generated.
never
(the default): the given property value is
not generated within the database.
insert
: the given property value is generated on
insert, but is not regenerated on subsequent updates. Properties like
created-date fall into this category. Even though version and timestamp properties can be
marked as generated, this option is not available.
always
: the property value is generated both on
insert and on update.
To mark a property as generated, use
@Generated
.
Hibernate allows you to customize the SQL it uses to read and write the values of columns mapped to simple properties. For example, if your database provides a set of data encryption functions, you can invoke them for individual columns like this:
@Entity
class CreditCard {
@Column(name="credit_card_num")
@ColumnTransformer(
read="decrypt(credit_card_num)",
write="encrypt(?)")
public String getCreditCardNumber() { return creditCardNumber; }
public void setCreditCardNumber(String number) { this.creditCardNumber = number; }
private String creditCardNumber;
}
or in XML
<property name="creditCardNumber">
<column
name="credit_card_num"
read="decrypt(credit_card_num)"
write="encrypt(?)"/>
</property>
You can use the plural form
@ColumnTransformers
if more than one columns need
to define either of these rules.
If a property uses more that one column, you must use the
forColumn
attribute to specify which column, the
expressions are targeting.
@Entity
class User {
@Type(type="com.acme.type.CreditCardType")
@Columns( {
@Column(name="credit_card_num"),
@Column(name="exp_date") } )
@ColumnTransformer(
forColumn="credit_card_num",
read="decrypt(credit_card_num)",
write="encrypt(?)")
public CreditCard getCreditCard() { return creditCard; }
public void setCreditCard(CreditCard card) { this.creditCard = card; }
private CreditCard creditCard;
}
Hibernate applies the custom expressions automatically whenever the
property is referenced in a query. This functionality is similar to a
derived-property formula
with two differences:
The property is backed by one or more columns that are exported as part of automatic schema generation.
The property is read-write, not read-only.
The write
expression, if specified, must contain
exactly one '?' placeholder for the value.
Auxiliary database objects allow for the CREATE and DROP of
arbitrary database objects. In conjunction with Hibernate's schema
evolution tools, they have the ability to fully define a user schema
within the Hibernate mapping files. Although designed specifically for
creating and dropping things like triggers or stored procedures, any SQL
command that can be run via a
java.sql.Statement.execute()
method is valid (for
example, ALTERs, INSERTS, etc.). There are essentially two modes for
defining auxiliary database objects:
The first mode is to explicitly list the CREATE and DROP commands in the mapping file:
<hibernate-mapping>
...
<database-object>
<create>CREATE TRIGGER my_trigger ...</create>
<drop>DROP TRIGGER my_trigger</drop>
</database-object>
</hibernate-mapping>
The second mode is to supply a custom class that constructs the
CREATE and DROP commands. This custom class must implement the
org.hibernate.mapping.AuxiliaryDatabaseObject
interface.
<hibernate-mapping>
...
<database-object>
<definition class="MyTriggerDefinition"/>
</database-object>
</hibernate-mapping>
Additionally, these database objects can be optionally scoped so that they only apply when certain dialects are used.
<hibernate-mapping>
...
<database-object>
<definition class="MyTriggerDefinition"/>
<dialect-scope name="org.hibernate.dialect.Oracle9iDialect"/>
<dialect-scope name="org.hibernate.dialect.Oracle10gDialect"/>
</database-object>
</hibernate-mapping>
This feature is not supported in Annotations
Copyright © 2004 Red Hat, Inc.