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.
Note que, embora muitos usuários do Hibernate escolham gravar o XML manualmente, existem diversas ferramentas para gerar o documento de mapeamento, incluindo o XDoclet Middlegen e AndroMDA.
Vamos iniciar com um exemplo de mapeamento:
<?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
: verifica as colunas de versão/timestamp
all
: verifica todas as colunas
dirty
: verifica as colunas modificadas, permitindo algumas atualizações concorrentes
none
: não utiliza o bloqueio otimista
Nós realmente recomendamos que você utilize as colunas de versão/timestamp para o bloqueio otimista com o Hibernate. Esta é a melhor estratégia em relação ao desempenho e é a única estratégia que trata corretamente as modificações efetuadas em instâncias desconectadas (por exemplo, quando Session.merge()
é utilizado).
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 as tabelas para sincronizar com esta entidade, garantindo que a auto-liberação ocorra corretamente, e que as consultas para esta entidade derivada não retornem dados desatualizados. O <subselect>
está disponível tanto como um atributo como um elemento mapeado aninhado.
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) |
|
É perfeitamente aceitável uma classe persitente nomeada ser uma interface. Você deverá então declarar as classes implementadas desta interface utilizando o elemento <subclass>
. Você pode persistir qualquer classe interna estática. Você deverá especificar o nome da classe usando a forma padrão, por exemplo: eg.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>
| |
| |
| |
| |
|
Se a função name
não for declarada, considera-se que a classe não tem a propriedade de identificação.
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>
Todos os geradores implementam a interface org.hibernate.id.IdentifierGenerator
. Esta é uma interface bem simples. Algumas aplicações podem prover suas próprias implementações especializadas, entretanto, o Hibernate disponibiliza um conjunto de implementações internamente. Há nomes de atalhos para estes geradores internos, conforme segue abaixo:
increment
gera identificadores dos tipos long
, short
ou int
que são únicos apenas quando nenhum outro processo está inserindo dados na mesma tabela. Não utilize em ambientes de cluster.
identity
suporta colunas de identidade em DB2, MySQL, Servidor MS SQL, Sybase e HypersonicSQL. O identificador retornado é do tipo long
, short
ou int
.
sequence
utiliza uma seqüência em DB2, PostgreSQL, Oracle, SAP DB, McKoi ou um gerador no Interbase. O identificador de retorno é do tipo long
, short
ou int
.
hilo
utiliza um algoritmo hi/lo para gerar de forma eficiente identificadores do tipo long
, short
ou int
, a partir de uma tabela e coluna fornecida (por padrão hibernate_unique_key
e next_hi
) como fonte para os valores hi. O algoritmo hi/lo gera identificadores que são únicos apenas para um banco de dados específico.
seqhilo
utiliza um algoritmo hi/lo para gerar de forma eficiente identificadores do tipo long
, short
ou int
, a partir de uma seqüência de banco de dados fornecida.
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
utiliza um string GUID gerado pelo banco de dados no Servidor MS SQL e MySQL.
native
seleciona entre identity
, sequence
ou hilo
dependendo das capacidades do banco de dados utilizado.
assigned
deixa a aplicação definir um identificador para o objeto antes que o save()
seja chamado. Esta é a estratégia padrão caso nenhum elemento <generator>
seja especificado.
select
retorna a chave primária recuperada por um trigger do banco de dados, selecionando uma linha pela chave única e recuperando o valor da chave primária.
foreign
utiliza o identificador de um outro objeto associado. Normalmente utilizado em conjunto com uma associação de chave primária do tipo <one-to-one>
.
sequence-identity
uma estratégia de geração de seqüência especializada que use uma seqüência de banco de dados para a geração de valor atual, mas combina isto com JDBC3 getGeneratedKeys para de fato retornar o valor do identificador gerado como parte da execução de instrução de inserção. Esta estratégia é somente conhecida para suportar drivers da Oracle 10g, focados em JDK 1.4. Note que os comentários sobre estas instruções de inserção estão desabilitados devido a um bug nos drivers da Oracle.
Os geradores hilo
e seqhilo
fornecem duas implementações alternativas do algoritmo hi/lo, uma solução preferencial para a geração de identificadores. A primeira implementação requer uma tabela "especial" do banco de dados para manter o próximo valor "hi" disponível. A segunda utiliza uma seqüência do estilo Oracle (quando suportado).
<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>
Infelizmente, você não pode utilizar hilo
quando estiver fornecendo sua própria Connection
para o Hibernate. Quando o Hibernate estiver usando uma fonte de dados do servidor de aplicações para obter conexões suportadas com JTA, você precisará configurar adequadamente o hibernate.transaction.manager_lookup_class
.
O UUID contém: o endereço IP, hora de início da JVM que é com precisão de um quarto de segundo, a hora do sistema e um valor contador que é único dentro da JVM. Não é possível obter o endereço MAC ou um endereço de memória do código Java, portanto este é o melhor que pode ser feito sem utilizar JNI.
Para bancos de dados que suportam colunas de identidade (DB2, MySQL, Sybase, MS SQL), você pode utilizar uma geração de chave identity
. Para bancos de dados que suportam sequencias (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB) você pode utilizar a geração de chaves no estilo sequence
. As duas estratégias requerem duas consultas SQL para inserir um novo objeto.
<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>
Para desenvolvimento multi-plataforma, a estratégia native
irá escolher entre as estratégias identity
, sequence
e hilo
, dependendo das capacidades do banco de dados utilizado.
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.
A escolha do gerador assigned
faz com que o Hibernate utilize unsaved-value="undefined"
. Isto força o Hibernate ir até o banco de dados para determinar se uma instância está transiente ou desacoplada, a não ser que haja uma versão ou uma propriedade de timestamp, ou que você definia Interceptor.isUnsaved()
.
O Hibernate não gera DDL com triggers, apenas para sistemas legados.
<id name="id" type="long" column="person_id">
<generator class="select">
<param name="key">socialSecurityNumber</param>
</generator>
</id>
No exemplo acima, há uma única propriedade com valor nomeada socialSecurityNumber
definida pela classe, uma chave natural, e uma chave substituta nomeada person_id
cujo valor é gerado por um 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>
Iniciando com a liberação 3.2.3, existem dois novos geradores que representam uma reavaliação de dois diferentes aspectos da geração identificadora. O primeiro aspecto é a portabilidade do banco de dados, o segundo é a otimização. A otimização significa que você não precisa questionar o banco de dados a cada solicitação para um novo valor de identificador. Estes dois geradores possuem por intenção substituir alguns dos geradores nomeados acima, começando em 3.3.x. No entanto, eles estão incluídos nas liberações atuais e podem ser referenciados pelo FQN.
A primeira destas novas gerações é a org.hibernate.id.enhanced.SequenceStyleGenerator
que primeiramente é uma substituição para o gerador sequence
e, segundo, um melhor gerador de portabilidade que o native
. Isto é devido ao native
normalmente escolher entre identity
e sequence
, que são semânticas extremamente diferentes das quais podem causar problemas súbitos em portabilidade de observação de aplicativos. No entanto, o org.hibernate.id.enhanced.SequenceStyleGenerator
atinge a portabilidade numa maneira diferente. Ele escolhe entre uma tabela ou uma seqüência no banco de dados para armazenar seus valores de incrementação, dependendo nas capacidades do dialeto sendo usado. A diferença entre isto e o native
é que o armazenamento baseado na tabela e seqüência possuem exatamente a mesma semântica. Na realidade, as seqüências são exatamente o que o Hibernate tenta imitar com os próprios geradores baseados na tabela. Este gerador possui um número de parâmetros de configuração:
sequence_name
(opcional - valor padrão hibernate_sequence
) o nome da seqüência ou tabela a ser usada.
initial_value
(opcional - padrão para 1
) O valor inicial a ser restaurado a partir da seqüência/tabela. Em termos da criação de seqüência, isto é análogo à cláusula tipicamente nomeada "STARTS WITH".
increment_size
(opcional - padrão para 1
): o valor pelo qual as chamadas para a seqüência/tabela devem diferenciar-se. Nos termos da criação da seqüência, isto é análogo à cláusula tipicamente nomeada "INCREMENT BY".
force_table_use
(opcional - padrão para false
): devemos forçar o uso de uma tabela como uma estrutura de reforço, mesmo que o dialeto possa suportar a seqüência?
value_column
(opcional - padrão para next_val
): apenas relevante para estruturas de tabela, este é o nome da coluna onde na tabela que é usado para manter o valor.
optimizer
(optional - defaults to none
): See Seção 5.1.2.3.1, “Otimização do Gerador de Identificação”
O segundo destes novos geradores é o org.hibernate.id.enhanced.TableGenerator
, que primeiramente é uma substituição para o gerador table
, mesmo que isto funcione muito mais como um org.hibernate.id.MultipleHiLoPerTableGenerator
, e segundo, como uma reimplementação do org.hibernate.id.MultipleHiLoPerTableGenerator
que utiliza a noção dos otimizadores pugláveis. Basicamente, este gerador define uma tabela capacitada de manter um número de valores de incremento simultâneo pelo uso múltiplo de filas de chaves distintas. Este gerador possui um número de parâmetros de configuração.
table_name
(opcional - padrão para hibernate_sequences
): O nome da tabela a ser usado.
value_column_name
(opcional - padrão para next_val
): o nome da coluna na tabela que é usado para manter o valor.
segment_column_name
(opcional - padrão para sequence_name
) O nome da coluna da tabela que é usado para manter a "chave de segmento". Este é o valor que identifica qual valor de incremento a ser usado.
base
(opcional - padrão para default
) O valor da "chave de segmento" para o segmento pelo qual nós queremos obter os valores de incremento para este gerador.
segment_value_length
(opcional - padrão para 255
): Usado para a geração do esquema. O tamanho da coluna para criar esta coluna de chave de segmento.
initial_value
(opcional - valor padrão para 1
): O valor inicial a ser restaurado a partir da tabela.
increment_size
(opcional - padrão para 1
): O valor pelo qual as chamadas subseqüentes para a tabela devem diferir-se.
optimizer
(optional - defaults to ??
): See Seção 5.1.2.3.1, “Otimização do Gerador de Identificação”.
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 (Seção 5.1.2.3, “Aprimoração dos geradores de identificador” support this operation.
none
(geralmente este é o padrão, caso nenhum otimizador for especificado): isto não executará quaisquer otimizações e alcançará o banco de dados para cada e toda solicitação.
hilo
: aplica-se ao algoritmo em volta dos valores restaurados do banco de dados. Espera-se que os valores a partir do banco de dados para este otimizador sejam seqüenciais. Os valores restaurados a partir da estrutura do banco de dados para este otimizador indica um "número de grupo". O increment_size
é multiplicado pelo valor em memória para definir um grupo "hi value".
pooled
: assim como o caso do hilo
, este otimizador tenta minimizar o número de tentativas no banco de dados. No entanto, nós simplesmente implementamos o valor de inicialização para o "próximo grupo" na estrutura do banco de dados ao invés do valor seqüencial na combinação com um algoritmo de agrupamento em memória. Neste caso, o increment_size
refere-se aos valores de entrada a partir do banco de dados.
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 versão ou timestamp de uma propriedade nunca deve ser nula para uma instância desconectada, assim o Hibernate irá identificar qualquer instância com uma versão nula ou timestamp como transiente, não importando qual outra estratégia unsaved-value
tenha sido especificada. A declaração de uma versão nula ou a propriedade timestamp é um caminho fácil para tratar problemas com reconexões transitivas no Hibernate, especialmente úteis para pessoas utilizando identificadores atribuídos ou chaves compostas.
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|." />
| |
| |
| |
| |
| |
|
Observe que o <timestamp>
é equivalente a <version type="timestamp">
. E <timestamp source="db">
é equivalente a <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:
O nome de um tipo básico de Hibernate: integer, string, character, date, timestamp, float, binary, serializable, object, blob
, etc.
O nome da classe Java com um tipo básico padrão: int, float, char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob
, etc.
O nome da classe Java serializável
O nome da classe de um tipo customizado: 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
O elemento <property>
declara uma propriedade de estilo JavaBean de uma classe.
<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 pode ser:
O nome de um tipo básico de Hibernate: integer, string, character, date, timestamp, float, binary, serializable, object, blob
, etc.
O nome da classe Java com um tipo básico padrão: int, float, char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob
, etc.
O nome da classe Java serializável
O nome da classe de um tipo customizado: com.illflow.type.MyCustomType
, etc.
Se você não especificar um tipo, o Hibernate irá utilizar reflexão sobre a propriedade nomeada para ter uma idéia do tipo de Hibernate correto. O Hibernate tentará interpretar o nome da classe retornada, usando as regras 2, 3 e 4 nesta ordem. Em certos casos, você ainda precisará do atributo type
. Por exemplo, para distinguir entre Hibernate.DATE
e Hibernate.TIMESTAMP
, ou para especificar um tipo customizado.
A função access
permite que você controle como o Hibernate irá acessar a propriedade em tempo de execução. Por padrão, o Hibernate irá chamar os métodos get/set da propriedades. Se você especificar access="field"
, o Hibernate irá bipassar os metodos get/set, acessando o campo diretamente, usando reflexão. Você pode especificar sua própria estratégia para acesso da propriedade criando uma classe que implemente a interface org.hibernate.property.PropertyAccessor
.
Um recurso especialmente poderoso é o de propriedades derivadas. Estas propriedades são por definição somente leitura, e o valor da propriedade é calculado em tempo de execução. Você declara este cálculo como uma expressão SQL, que traduz para cláusula SELECT
de uma subconsulta da consulta SQL que carrega a instância:
<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 )"/>
Observe que você pode referenciar as entidades da própria tabela, através da não declaração de um alias para uma coluna particular. Isto seria o customerId
no exemplo dado. Observe também que você pode usar o mapeamento de elemento aninhado <formula>
, se você não gostar de usar o atributo.
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>
| |
| |
| |
| |
| |
| |
| |
|
A tag filha <property>
acrescenta a propriedade de mapeamento da classe filha para colunas de uma tabela.
O elemento <component>
permite um sub-elemento <parent>
mapeie uma propriedade da classe do componente como uma referencia de volta para a entidade que o contém.
The <dynamic-component>
element allows a Map
to be mapped as a component, where the property names refer to keys of the map. See Seção 9.5, “Componentes Dinâmicos” 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 Capítulo 10, Mapeamento de Herança .
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" />
| |
| |
| |
| |
|
Valores atuais de uma coluna discriminada são especificados pela função discriminator-value
da <class>
e elementos da <subclass>
.
Usando o atributo formula
você pode declarar uma expressão SQL arbitrária que será utilizada para avaliar o tipo de uma linha. Por exemplo:
<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 Capítulo 10, Mapeamento de Herança .
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>
| |
| |
| |
|
A coluna discriminatória não é requerida para esta estratégia de mapeamento.
For information about inheritance mappings see Capítulo 10, Mapeamento de Herança .
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>
| |
| |
| |
| |
| |
|
Por exemplo, a informação de endereço para uma pessoa pode ser mapeada para uma tabela separada, enquanto preservando o valor da semântica de tipos para todas as propriedades:
<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>
...
Esta característica é útil apenas para modelos de dados legados. Nós recomendamos menos tabelas do que classes e um modelo de domínio fine-grained. Porém, é útil para ficar trocando entre estratégias de mapeamento de herança numa hierarquia simples, como explicaremos mais a frente.
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 Seção 11.11, “Persistência Transitiva” 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.
Exemplo 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.
Exemplo 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
.
Exemplo 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 Seção 11.11, “Persistência Transitiva” for a full explanation. Note that single valued, many-to-one and one-to-one, associations do not support orphan delete.
Segue abaixo uma amostra de uma típica declaração many-to-one
:
<many-to-one name="product" class="Product" column="PRODUCT_ID"/>
O atributo property-ref
deve apenas ser usado para mapear dados legados onde uma chave exterior se refere à uma chave exclusiva da tabela associada que não seja a chave primária. Este é um modelo relacional desagradável. Por exemplo, suponha que a classe Product
tenha um número seqüencial exclusivo, que não seja a chave primária. O atributo unique
controla a geração de DDL do Hibernate com a ferramenta SchemaExport.
<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>
Então o mapeamento para OrderItem
poderia usar:
<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>
No entanto, isto não é recomendável.
Se a chave exclusiva referenciada engloba múltiplas propriedades da entidade associada, você deve mapear as propriedades referenciadas dentro de um elemento chamado <properties>
Se a chave exclusiva referenciada é a propriedade de um componente, você pode especificar um caminho para a propriedade:
<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.
Exemplo 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" />
| |
| |
| |
| |
| |
| |
| |
| |
| |
|
Associações de chave primária não necessitam de uma coluna extra de tabela. Se duas linhas forem relacionadas pela associação, então as duas linhas da tabela dividem o mesmo valor da chave primária. Assim, se você quiser que dois objetos sejam relacionados por uma associação de chave primária, você deve ter certeza que foram atribuídos com o mesmo valor identificador.
Para uma associação de chave primária, adicione os seguintes mapeamentos em Employee
e Person
, respectivamente:
<one-to-one name="person" class="Person"/>
<one-to-one name="employee" class="Employee" constrained="true"/>
Agora devemos assegurar que as chaves primárias de linhas relacionadas nas tabelas PERSON e EMPLOYEE são iguais. Nós usamos uma estratégia especial de geração de identificador do Hibernate chamada 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>
Uma nova instância de Person
é atribuída com o mesmo valor da chave primária da instância de Employee
referenciada com a propriedade employee
daquela 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>
Nós recomendamos com ênfase que você implemente equals()
e hashCode()
para comparar as propriedades da chave natural da entidade.
Este mapeamento não pretende ser utilizado com entidades com chaves naturais primárias.
mutable
(opcional, padrão false
): Por padrão, propriedades naturais identificadoras são consideradas imutáveis (constante).
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>
| |
| |
| |
| |
| |
|
O elemento <properties>
permite a definição de um grupo com nome, lógico de propriedades de uma classe. A função mais importante do construtor é que ele permite que a combinação de propriedades seja o objetivo de uma property-ref
. É também um modo conveninente para definir uma restrição única de múltiplas colunas. Por exemplo:
<properties name="logicalName" insert="true|false" update="true|false" optimistic-lock="true|false" unique="true|false" > <property ...../> <many-to-one .... /> ........ </properties>
| |
| |
| |
| |
|
Por exemplo, se temos o seguinte mapeamento de <properties>
:
<class name="Person">
<id name="personNumber"/>
...
<properties name="name"
unique="true" update="false">
<property name="firstName"/>
<property name="initial"/>
<property name="lastName"/>
</properties>
</class>
Então podemos ter uma associação de dados legados que referem a esta chave exclusiva da tabela Person
, ao invés de se referirem a chave primária:
<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
}
Nós não recomendamos o uso deste tipo de coisa fora do contexto de mapeamento de dados legados.
The hbm.xml structure has some specificities naturally not present when using annotations, let's describe them briefly.
Todos os mapeamentos de XML devem declarar o doctype exibido. O DTD atual pode ser encontrado na URL abaixo, no diretório hibernate-x.x.x/src/org/ hibernate
ou no hibernate3.jar
. O Hibernate sempre irá procurar pelo DTD inicialmente no seu classpath. Se você tentar localizar o DTD usando uma conexão de internet, compare a declaração do seu DTD com o conteúdo do seu classpath.
O Hibernate irá primeiro tentar solucionar os DTDs em seus classpath. Isto é feito, registrando uma implementação org.xml.sax.EntityResolver
personalizada com o SAXReader que ele utiliza para ler os arquivos xml. Este EntityResolver
personalizado, reconhece dois nomes de espaço de sistemas Id diferentes:
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.
Um user namespace
é reconhecido quando um solucionador encontra um sistema Id, utilizando um protocolo URL de classpath://
. O solucionador tentará solucionar estas entidades através do carregador de classe do contexto de thread atual (1) e o carregador de classe (2) que carregou as classes do Hibernate.
Um exemplo de utilização do espaço de nome do usuário:
<?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>
Onde types.xml
é um recurso no pacote your.domain
e contém um typedef personalizado.
Este elemento possui diversos atributos opcionais. Os atributos schema
e catalog
especificam que tabelas referenciadas neste mapeamento pertencem ao esquema e/ou ao catálogo nomeado. Se especificados, os nomes das tabelas serão qualificados no esquema ou catálogo dado. Se não, os nomes das tabelas não serão qualificados. O atributo default-cascade
especifica qual estilo de cascata será considerado pelas propriedades e coleções que não especificarem uma função cascade
. A função auto-import
nos deixa utilizar nomes de classes não qualificados na linguagem de consulta, por padrão.
<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" />
| |
| |
| |
| |
| |
| |
|
Se você tem duas classes persistentes com o mesmo nome (não qualificadas), você deve ajustar auto-import="false"
. Caso você tentar ajustar duas classes para o mesmo nome "importado", isto resultará numa exceção.
Observe que o elemento hibernate-mapping
permite que você aninhe diversos mapeamentos de <class>
persistentes, como mostrado abaixo. Entretanto, é uma boa prática (e esperado por algumas ferramentas) o mapeamento de apenas uma classe persistente simples (ou uma hierarquia de classes simples) em um arquivo de mapeamento e nomeá-la após a superclasse persistente, por exemplo: Cat.hbm.xml
, Dog.hbm.xml
, ou se estiver usando herança, 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" />
| |
| |
| |
| |
| |
|
Nós recomendamos que para sistemas que o desempenho deletar seja importante, todas as chaves devem ser definidas on-delete="cascade"
. O Hibernate irá usar uma restrição a nível de banco de dados ON CASCADE DELETE
, ao invés de muitas instruções DELETE
. Esteja ciente que esta característica é um atalho da estratégia usual de bloqueio otimista do Hibernate para dados versionados.
As funções not-null
e update
são úteis quando estamos mapeando uma associação unidirecional um para muitos. Se você mapear uma associação unidirecional um para muitos para uma chave exterior não-nula, você deve declarar a coluna chave usando <key not-null="true">
.
Vamos supor que a sua aplicação tenha duas classes persistentes com o mesmo nome, e você não quer especificar o nome qualificado do pacote nas consultas do Hibernate. As Classes deverão ser "importadas" explicitamente, de preferência contando com auto-import="true"
. Você pode até importar classes e interfaces que não estão explicitamente mapeadas:
<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.
Qualquer elemento de mapeamento que aceita uma função column
irá aceitar alternativamente um sub-elemento <column>
. Da mesma forma, <formula>
é uma alternativa para a função formula
.
<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>
A maioria das funções no column
fornecem um significado de junção do DDL durante a geração automática do esquema. As funções read
e write
permitem que você especifique o SQL personalizado, do qual o Hibernate usará para acessar o valor da coluna. Consulte a discussão da column read and write expressions para maiores informações.
Os elementos column
e formula
podem até ser combinados dentro da mesma propriedade ou associação mapeando para expressar, por exemplo, condições de associações exóticas.
<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>
Os objetos de nível de linguagem Java são classificados em dois grupos, em relação ao serviço de persistência:
Uma entidade existe independentemente de qualquer outro objeto guardando referências para a entidade. Em contraste com o modelo usual de Java que um objeto não referenciado é coletado pelo coletor de lixo. Entidades devem ser explicitamente salvas ou deletadas (exceto em operações de salvamento ou deleção que possam ser executada em cascata de uma entidade pai para seus filhos). Isto é diferente do modelo ODMG de persistência do objeto por acessibilidade e se refere mais à forma como os objetos de aplicações são geralmente usados em grandes sistemas. Entidades suportam referências circulares e comuns. Eles podem ser versionados.
O estado persistente da entidade consiste de referências para outras entidades e instâncias de tipos de valor. Valores são primitivos: coleções (não o que tem dentro de uma coleção), componentes e certos objetos imutáveis. Entidades distintas, valores (em coleções e componentes particulares) são persistidos e apagados por acessibilidade. Visto que objetos de valor (e primitivos) são persistidos e apagados junto com as entidades que os contém e não podem ser versionados independentemente. Valores têm identidade não independente, assim eles não podem ser comuns para duas entidades ou coleções.
Até agora, estivemos usando o termo "classe persistente" para referir às entidades. Continuaremos a fazer isto. No entanto, nem todas as classes definidas pelo usuário com estados persistentes são entidades. Um componente é uma classe de usuário definida com valores semânticos. Uma propriedade de Java de tipo java.lang.String
também tem um valor semântico. Dada esta definição, nós podemos dizer que todos os tipos (classes) fornecidos pelo JDK têm tipo de valor semântico em Java, enquanto que tipos definidos pelo usuário, podem ser mapeados com entidade ou valor de tipo semântico. Esta decisão pertence ao desenvolvedor da aplicação. Uma boa dica para uma classe de entidade em um modelo de domínio são referências comuns para uma instância simples daquela classe, enquanto a composição ou agregação geralmente se traduz para um tipo de valor.
Iremos rever ambos os conceitos durante todo o guia de referência.
O desafio é mapear o sistema de tipo de Java e a definição do desenvolvedor de entidades e tipos de valor para o sistema de tipo SQL/banco de dados. A ponte entre ambos os sistemas é fornecida pelo Hibernate. Para entidades que usam <class>
, < subclass>
e assim por diante. Para tipos de valores nós usamos <property>
, <component>
, etc, geralmente com uma função type
. O valor desta função é o nome de um tipo de mapeamento do Hibernate. O Hibernate fornece muitos mapeamentos imediatos para tipos de valores do JDK padrão. Você pode escrever os seus próprios tipos de mapeamentos e implementar sua estratégia de conversão adaptada, como você.
Todos os tipos internos do hibernate exceto coleções, suportam semânticas nulas com a exceção das coleções.
Os tipos de mapeamento básicos fazem parte da categorização do seguinte:
integer, long, short, float, double, character, byte, boolean, yes_no, true_false
Tipos de mapeamentos de classes primitivas ou wrapper Java específicos (vendor-specific) para tipos de coluna SQL. Boolean, boolean, yes_no
são todas codificações alternativas para um boolean
ou java.lang.Boolean
do Java.
string
Um tipo de mapeamento de java.lang.String
para VARCHAR
(ou VARCHAR2
no Oracle).
date, time, timestamp
Tipos de mapeamento de java.util.Date
e suas subclasses para os tipos SQL DATE
, TIME
e TIMESTAMP
(ou equivalente).
calendar, calendar_date
Tipo de mapeamento de java.util.Calendar
para os tipos SQL TIMESTAMP
e DATE
(ou equivalente).
big_decimal, big_integer
Tipo de mapeamento de java.math.BigDecimal
and java.math.BigInteger
para NUMERIC
(ou NUMBER
no Oracle).
locale, timezone, currency
Tipos de mapeamentos de java.util.Locale
, java.util.TimeZone
e java.util.Currency
para VARCHAR
(ou VARCHAR2
no Oracle). Instâncias de f Locale
e Currency
são mapeados para seus códigos ISO. Instâncias de TimeZone
são mapeados para seu ID
.
class
Um tipo de mapeamento de java.lang.Class
para VARCHAR
(ou VARCHAR2
no Oracle). Uma Class
é mapeada pelo seu nome qualificado (completo).
binary
Mapeia matrizes de bytes para um tipo binário de SQL apropriado.
text
Maps long Java strings to a SQL LONGVARCHAR
or TEXT
type.
image
Maps long byte arrays to a SQL LONGVARBINARY
.
serializable
Mapeia tipos Java serializáveis para um tipo binário SQL apropriado. Você pode também indicar o tipo serializable
do Hibernate com o nome da classe ou interface Java serializável que não é padrão para um tipo básico.
clob, blob
Tipos de mapeamentos para as classes JDBC java.sql.Clob
and java.sql.Blob
. Estes tipos podem ser inconvenientes para algumas aplicações, visto que o objeto blob ou clob não pode ser reusado fora de uma transação. Além disso, o suporte de driver é imcompleto e inconsistente.
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
Mapeamento de tipos para, os geralmente considerados, tipos mutáveis de Java. Isto é onde o Hibernate faz determinadas otimizações apropriadas somente para tipos imutáveis de Java, e a aplicação trata o objeto como imutável. Por exemplo, você não deve chamar Date.setTime()
para uma instância mapeada como imm_timestamp
. Para mudar o valor da propriedade, e ter a mudança feita persistente, a aplicação deve atribuir um novo objeto (nonidentical) à propriedade.
Identificadores únicos das entidades e coleções podem ser de qualquer tipo básico exceto binary
, blob
ou clob
. (Identificadores compostos também são permitidos. Leia abaixo para maiores informações.
Os tipos de valores básicos têm suas constantes Type
correspondentes definidas em org.hibernate.Hibernate
. Por exemplo, Hibernate.STRING
representa o tipo string
.
É relativamente fácil para desenvolvedores criarem seus próprios tipos de valores. Por exemplo, você pode querer persistir propriedades do tipo java.lang.BigInteger
para colunas VARCHAR
. O Hibernate não fornece um tipo correspondente para isso. Mas os tipos adaptados não são limitados a mapeamento de uma propriedade, ou elemento de coleção, a uma única coluna da tabela. Assim, por exemplo, você pode ter uma propriedade Java getName()
/setName()
do tipo java.lang.String
que é persistido para colunas FIRST_NAME
, INITIAL
, SURNAME
.
Para implementar um tipo personalizado, implemente org.hibernate.UserType
ou org.hibernate.CompositeUserType
e declare propriedades usando o nome qualificado da classe do tipo. Veja org.hibernate.test.DoubleStringType
para outras funcionalidades.
<property name="twoStrings" type="org.hibernate.test.DoubleStringType">
<column name="first_string"/>
<column name="second_string"/>
</property>
Observe o uso da tag <column>
para mapear uma propriedade para colunas múltiplas.
As interfaces CompositeUserType
, EnhancedUserType
, UserCollectionType
, e UserVersionType
fornecem suporte para usos mais especializados.
Você mesmo pode fornecer parâmetros a um UserType
no arquivo de mapeamento. Para isto, seu UserType
deve implementar a interface org.hibernate.usertype.ParameterizedType
. Para fornecer parâmetros a seu tipo personalizado, você pode usar o elemento <type>
em seus arquivos de mapeamento.
<property name="priority">
<type name="com.mycompany.usertypes.DefaultValueIntegerType">
<param name="default">0</param>
</type>
</property>
O UserType
pode agora recuperar o valor para o parâmetro chamado padrão
da Propriedade
do passado a ele.
Se você usar freqüentemente um determinado UserType
, pode ser útil definir um nome mais curto para ele. Você pode fazer isto usando o elemento <typedef>
. Typedefs atribui um nome a um tipo personalizado, e pode também conter uma lista de valores de parâmetro padrão se o tipo for parametrizado.
<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">
<param name="default">0</param>
</typedef>
<property name="priority" type="default_zero"/>
Também é possível substituir os parâmetros fornecidos em um tipo de definição em situações de caso a caso, utilizando tipos de parâmetros no mapeamento da propriedade.
Apesar da rica variedade, os tipos construídos do Hibernate e suporte para componentes raramente irão utilizar um tipo de padrão, no entanto, é considerado uma boa idéia, utilizar tipos customizados para classes não entidade que ocorrem com freqüência em seu aplicativo. Por exemplo, uma classe MonetaryAmount
é um bom candidato para um CompositeUserType
, apesar de poder ter sido mapeado facilmente como um componente. Uma motivação para isto é a abstração. Com um tipo padronizado, seus documentos de mapeamento seriam colocados à prova contra mudanças possíveis na forma de representação de valores monetários.
É possível fornecer mais de um mapeamento para uma classe persistente em específico. Neste caso, você deve especificar um nome de entidade para as instâncias das duas entidades mapeadas não se tornarem ambíguas. Por padrão, o nome da entidade é o mesmo do nome da classe. O Hibernate o deixa especificar o nome de entidade quando estiver trabalhando com objetos persistentes, quando escrever consultas, ou ao mapear associações para a entidade nomeada.
<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>
Note como as associações são agora especificadas utilizando o entity-name
ao invés da class
.
This feature is not supported in Annotations
Você poderá forçar o Hibernate a quotar um identificador no SQL gerado, anexando o nome da tabela ou coluna aos backticks no documento de mapeamento. O Hibernate usará o estilo de quotação correto para o SQL Dialect
. Geralmente são quotas dúplas, mas parênteses para o Servidor SQL e backticks para MeuSQL.
@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>
Propriedades Geradas são propriedades que possuem seus valores gerados pelo banco de dados. Como sempre, os aplicativos do Hibernate precisavam renovar
objetos que contenham qualquer propriedade para qual o banco de dados estivesse gerando valores. No entanto, vamos permitir que o aplicativo delegue esta responsabilidade ao Hibernate. Essencialmente, quando o Hibernate edita um SQL INSERT ou UPDATE para uma entidade que tem propriedades geradas definidas, ele edita imediatamente depois uma seleção para recuperar os valores gerados.
As propriedades marcadas como geradas devem ser não-inseríveis e não-atualizáveis. Somente versions, timestamps, e simple properties podem ser marcadas como geradas.
never
(padrão) - significa que o valor de propriedade dado não é gerado dentro do banco de dados.
insert
: informa que o valor de propriedade dado é gerado ao inserir, mas não é novamente gerado nas próximas atualizações. Propriedades do tipo data criada, se encaixam nesta categoria. Note que embora as propriedades version e timestamp podem ser marcadas como geradas, esta opção não está disponível.
always
- informa que o valor da propriedade é gerado tanto ao inserir quanto ao atualizar.
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;
}
O Hibernate aplica automaticamente as expressöes personalizadas a todo instante que a propriedade é referenciada numa consulta. Esta funcionalidade é parecida a uma formula
de propriedade-derivada com duas diferenças:
Esta propriedade é suportada por uma ou mais colunas que são exportadas como parte da geração do esquema automático.
Esta propriedade é de gravação-leitura, e não de leitura apenas.
Caso a expressão write
seja especificada, deverá conter um '?' para o valor.
Permite o uso dos comandos CREATE e DROP para criar e remover os objetos de banco de dados arbitrários. Juntamente às ferramentas de evolução do esquema do Hibernate, eles possuem a habilidade de definir completamente um esquema de usuário dentro dos arquivos de mapeamento do Hibernate. Embora criado especificamente para criar e remover algo como trigger ou procedimento armazenado, qualquer comando SQL que pode rodar através de um método java.sql.Statement.execute()
é válido. Existem dois módulos essenciais para definir objetos de banco de dados auxiliares:
O primeiro módulo é para listar explicitamente os comandos CREATE e DROP no arquivo de mapeamento:
<hibernate-mapping>
...
<database-object>
<create>CREATE TRIGGER my_trigger ...</create>
<drop>DROP TRIGGER my_trigger</drop>
</database-object>
</hibernate-mapping>
O segundo módulo é para fornecer uma classe padrão que sabe como construir os comandos CREATE e DROP. Esta classe padrão deve implementar a interface org.hibernate.mapping.AuxiliaryDatabaseObject
.
<hibernate-mapping>
...
<database-object>
<definition class="MyTriggerDefinition"/>
</database-object>
</hibernate-mapping>
Além disso, estes objetos de banco de dados podem ter um escopo opcional que só será aplicado quando certos dialetos forem utilizados.
<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.