Hibernate.org Community Documentation

- 上一页
- 下一页

## 第 5 章 对象/关系数据库映射基础（Basic O/R Mapping）

## 5.1. 映射定义（Mapping declaration）

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.

请注意，虽然很多 Hibernate 用户选择手写 XML 映射文档，但也有一些工具可以用来生成映射文档，包括 XDoclet、Middlegen 和 AndroMDA。

下面是一个映射的例子：

    <?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).

### 5.1.1. Entity

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（版本检查）`：检查 version/timestamp 字段

  - `all（全部）`：检查全部字段

  - `dirty（脏检查）`：只检察修改过的字段，允许某些并行更新

  - `none（不检查）`：不使用乐观锁定

  我们强烈建议你在 Hibernate 中使用 version/timestamp 字段来进行乐观锁定。这个选择可以优化性能，且能够处理对脱管实例的修改（例如：在使用 `Session.merge()` 的时候）。

## 提示

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; }

        ...

    }

定义这个实体用到的表为同步（synchronize），确保自动刷新（auto-flush）正确执行，并且依赖原实体的查询不会返回过期数据。在属性元素和嵌套映射元素中都可使用 `<subselect>`。

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"
    />

| `name`（可选）：持久化类（或者接口）的 Java 全限定名。 如果这个属性不存在，Hibernate 将假定这是一个非 POJO 的实体映射。
| `table`（可选 — 默认是类的非全限定名）：对应的数据库表名。
| `discriminator-value`（可选 — 默认和类名一样）：一个用于区分不同的子类的值，在多态行为时使用。它可以接受的值包括 `null` 和 `not null`。
| `mutable`（可选，默认值为 `true`）：表明该类的实例是可变的或者不可变的。
| `schema`（可选）：覆盖在根 `<hibernate-mapping>` 元素中指定的 schema 名字。
| `catalog`（可选）：覆盖在根 `<hibernate-mapping>` 元素中指定的 catalog 名字。
| `proxy`（可选）：指定一个接口，在延迟装载时作为代理使用。你可以在这里使用该类自己的名字。
| `dynamic-update`（可选，默认为 `false`）：指定用于 `UPDATE` 的 SQL 将会在运行时动态生成，并且只更新那些改变过的字段。
| `dynamic-insert`（可选，默认为 `false`）：指定用于 `INSERT` 的 SQL 将会在运行时动态生成，并且只包含那些非空值字段。
| `select-before-update`（可选，默认为 `false`）：指定 Hibernate 除非确定对象真正被修改了（如果该值为 true — 译注），否则不会执行 SQL `UPDATE` 操作。在特定场合（实际上，它只在一个瞬时对象（transient object）关联到一个新的 session 中时执行的 update() 中生效），这说明 Hibernate 会在 `UPDATE` 之前执行一次额外的 SQL `SELECT` 操作来决定是否确实需要执行 `UPDATE`。
| `polymorphisms` (optional - defaults to `implicit`): determines whether implicit or explicit query polymorphisms is used.
| `where`（可选）指定一个附加的 SQL `WHERE` 条件，在抓取这个类的对象时会一直增加这个条件。
| `persister`（可选）：指定一个定制的 `ClassPersister`。
| `batch-size`（可选,默认是 `1`）指定一个用于 根据标识符（identifier）抓取实例时使用的 "batch size"（批次抓取数量）。
| `optimistic-lock（乐观锁定）`（可选，默认是 `version`）：决定乐观锁定的策略。
(16) | `lazy`（可选）：通过设置 `lazy="false"`，所有的延迟加载（Lazy fetching）功能将被全部禁用（disabled）。
(17) | `entity-name` (optional - defaults to the class name): Hibernate3 allows a class to be mapped multiple times, potentially to different tables. It also allows entity mappings that are represented by Maps or XML at the Java level. In these cases, you should provide an explicit arbitrary name for the entity. See 第 4.4 节 “动态模型（Dynamic models）” and 第 20 章 XML 映射 for more information.
(18) | `check`（可选）：这是一个 SQL 表达式， 用于为自动生成的 schema 添加多行（multi-row）约束检查。
(19) | `rowid`（可选）：Hibernate 可以使用数据库支持的所谓的 ROWIDs，例如：Oracle 数据库，如果你设置这个可选的 `rowid`，Hibernate 可以使用额外的字段 `rowid` 实现快速更新。ROWID 是这个功能实现的重点，它代表了一个存储元组（tuple）的物理位置。
(20) | `subselect`（可选）：它将一个不可变（immutable）并且只读的实体映射到一个数据库的子查询中。当你想用视图代替一张基本表的时候，这是有用的，但最好不要这样做。更多的介绍请看下面内容。
(21) | `abstract`（可选）：用于在 `<union-subclass>` 的层次结构（hierarchies）中标识抽象超类。

若指明的持久化类实际上是一个接口，这也是完全可以接受的。之后你可以用元素 `<subclass>` 来指定该接口的实际实现类。你可以持久化任何 static（静态的）内部类。你应该使用标准的类名格式来指定类名，比如：`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.

### 5.1.2. Identifiers

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>

| `name`（可选）：标识属性的名字。
| `type`（可选）：一个 Hibernate 类型的名字。
| `column`（可选 — 默认为属性名）：主键字段的名字。
| `unsaved-value`（可选 — 默认为一个切合实际（sensible）的值）：一个特定的标识属性值，用来标志该实例是刚刚创建的，尚未保存。这可以把这种实例和从以前的 session 中装载过（可能又做过修改--译者注）但未再次持久化的实例区分开来。
| `access`（可选 — 默认为 `property`）：Hibernate 用来访问属性值的策略。

如果 `name` 属性不存在，会认为这个类没有标识属性。

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.

#### 5.1.2.1. Composite identifier

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.

##### 5.1.2.1.1. id as a property using a component type

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.

##### 5.1.2.1.2. Multiple id properties without identifier type

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>

##### 5.1.2.1.3. Multiple id properties with with a dedicated identifier type

`@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>

#### 5.1.2.2. Identifier generator

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>

##### 5.1.2.2.1. Various additional generators

所有的生成器都实现 `org.hibernate.id.IdentifierGenerator` 接口。这是一个非常简单的接口；某些应用程序可以选择提供他们自己特定的实现。当然，Hibernate 提供了很多内置的实现。下面是一些内置生成器的快捷名字：

`increment`

  用于为 `long`, `short` 或者 `int` 类型生成 唯一标识。只有在没有其他进程往同一张表中插入数据时才能使用。在集群下不要使用。

`identity`

  对 DB2，MySQL，MS SQL Server，Sybase 和 HypersonicSQL 的内置标识字段提供支持。返回的标识符是 `long`，`short` 或者 `int` 类型的。

`sequence`

  在 DB2，PostgreSQL，Oracle，SAP DB，McKoi 中使用序列（sequence）， 而在 Interbase 中使用生成器（generator）。返回的标识符是 `long`，`short` 或者 `int` 类型的。

`hilo`

  使用一个高/低位算法高效的生成 `long`，`short` 或者 `int` 类型的标识符。给定一个表和字段（默认分别是 `hibernate_unique_key` 和 `next_hi`）作为高位值的来源。高/低位算法生成的标识符只在一个特定的数据库中是唯一的。

`seqhilo`

  使用一个高/低位算法来高效的生成 `long`，`short` 或者 `int` 类型的标识符，给定一个数据库序列（sequence)的名字。

`uuid`

  Generates a 128-bit UUID based on a custom algorithm. The value generated is represented as a string of 32 hexidecimal digits. Users can also configure it to use a separator (config parameter "separator") which separates the hexidecimal digits into 8{sep}8{sep}4{sep}8{sep}4. Note specifically that this is different than the IETF RFC 4122 representation of 8-4-4-4-12. If you need RFC 4122 compliant UUIDs, consider using "uuid2" generator discussed below.

`uuid2`

  Generates a IETF RFC 4122 compliant (variant 2) 128-bit UUID. The exact "version" (the RFC term) generated depends on the pluggable "generation strategy" used (see below). Capable of generating values as `java.util.UUID`, `java.lang.String` or as a byte array of length 16 (`byte[16]`). The "generation strategy" is defined by the interface `org.hibernate.id.UUIDGenerationStrategy`. The generator defines 2 configuration parameters for defining which generation strategy to use:

  `uuid_gen_strategy_class`

    Names the UUIDGenerationStrategy class to use

  `uuid_gen_strategy`

    Names the UUIDGenerationStrategy instance to use

  Out of the box, comes with the following strategies:

  - `org.hibernate.id.uuid.StandardRandomStrategy` (the default) - generates "version 3" (aka, "random") UUID values via the `randomUUID` method of `java.util.UUID`

  - `org.hibernate.id.uuid.CustomVersionOneStrategy` - generates "version 1" UUID values, using IP address since mac address not available. If you need mac address to be used, consider leveraging one of the existing third party UUID generators which sniff out mac address and integrating it via the `org.hibernate.id.UUIDGenerationStrategy` contract. Two such libraries known at time of this writing include http://johannburkard.de/software/uuid/ and http://commons.apache.org/sandbox/id/uuid.html

`guid`

  在 MS SQL Server 和 MySQL 中使用数据库生成的 GUID 字符串。

`native`

  根据底层数据库的能力选择 `identity`、`sequence` 或者 `hilo` 中的一个。

`assigned`

  让应用程序在调用 `save()` 之前为对象分配一个标识符。这是 `<generator>` 元素没有指定时的默认生成策略。

`select`

  通过数据库触发器选择一些唯一主键的行并返回主键值来分配一个主键。

`foreign`

  使用另外一个相关联的对象的标识符。它通常和 `<one-to-one>` 联合起来使用。

`sequence-identity`

  一种特别的序列生成策略，它使用数据库序列来生成实际值，但将它和 JDBC3 的 getGeneratedKeys 结合在一起，使得在插入语句执行的时候就返回生成的值。目前为止只有面向 JDK 1.4 的 Oracle 10g 驱动支持这一策略。由于 Oracle 驱动程序的一个 bug，这些插入语句的注释被关闭了。

##### 5.1.2.2.2. 高/低位算法（Hi/Lo Algorithm）

`hilo` 和 `seqhilo` 生成器给出了两种 hi/lo 算法的实现， 这是一种很令人满意的标识符生成算法。第一种实现需要一个“特殊”的数据库表来保存下一个可用的“hi”值。 第二种实现使用一个 Oracle 风格的序列（在被支持的情况下）。

    <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>

可惜的是，你在为 Hibernate 自行提供 `Connection` 时无法使用 `hilo`。 当 Hibernate 使用 JTA 获取应用服务器的数据源连接时，你必须正确地配置 `hibernate.transaction.manager_lookup_class`。

##### 5.1.2.2.3. UUID 算法（UUID Algorithm ）

UUID 包含：IP 地址、JVM 的启动时间（精确到 1/4 秒）、系统时间和一个计数器值（在 JVM 中唯一）。 在 Java 代码中不可能获得 MAC 地址或者内存地址，所以这已经是我们在不使用 JNI 的前提下的能做的最好实现了。

##### 5.1.2.2.4. 标识字段和序列（Identity columns and Sequences）

对于内部支持标识字段的数据库（DB2、MySQL、Sybase 和 MS SQL），你可以使用 `identity` 关键字生成。对于内部支持序列的数据库（DB2、Oracle、PostgreSQL、Interbase、McKoi 和 SAP DB），你可以使用 `sequence` 风格的关键字生成。这两种方式对于插入一个新的对象都需要两次 SQL 查询。例如：

    <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>

对于跨平台开发，`native` 策略会从 `identity`、`sequence` 和 `hilo` 中进行选择，选择哪一个，这取决于底层数据库的支持能力。

##### 5.1.2.2.5. 程序分配的标识符（Assigned Identifiers）

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.

当选择 `assigned` 生成器时，除非有一个 version 或 timestamp 属性，或者你定义了 `Interceptor.isUnsaved()`，否则需要让 Hiberante 使用 `unsaved-value="undefined"`，强制 Hibernatet 查询数据库来确定一个实例是瞬时的（transient） 还是脱管的（detached）。

##### 5.1.2.2.6. 触发器实现的主键生成器（Primary keys assigned by triggers）

仅仅用于遗留的 schema 中（Hibernate 不能用触发器生成 DDL）。

    <id name="id" type="long" column="person_id">

            <generator class="select">

                    <param name="key">socialSecurityNumber</param>

            </generator>

    </id>

在上面的例子中，类定义了一个命名为 `socialSecurityNumber` 的具有唯一值的属性，它是一个自然键（natural key），命名为 `person_id` 的代理键（surrogate key）的值由触发器生成。

##### 5.1.2.2.7. Identity copy (foreign generator)

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>

#### 5.1.2.3. 增强的标识符生成器

从 3.2.3 版本开始，有两个代表不同标识符生成概念的新的生成器。第一个概念是数据库移植性；第二个是优化。优化表示你不需对每个新标识符的请求都查询数据库。从 3.3.x 开始，这两个新的生成器都是用来取代上面所述的生成器的。然而，它们也包括在当前版本里且可以由 FQN 进行引用。

这些生成器的第一个是 `org.hibernate.id.enhanced.SequenceStyleGenerator`，首先，它是作为 `sequence` 生成器的替代物，其次，它是比 `native` 具有更好移植性的生成器。这是因为 `native` 通常在 `identity` 和 `sequence` 之间选择，它有差别很大的 semantic，在移植时会导致潜在的问题。然而，`org.hibernate.id.enhanced.SequenceStyleGenerator` 以不同的方式实现移植性。它根据所使用的方言的能力，在数据库表或序列之间选择以存储其增量。这和 `native` 的区别是基于表或序列的存储具有恰好相同的 semantic。实际上，序列就是 Hibernate 试图用基于表的生成器来模拟的。这个生成器有如下的配置参数：

- `sequence_name`（可选 — 默认为 `hibernate_sequence`）：序列或表的名字

- `initial_value`（可选，默认为 `1`）：从序列/表里获取的初始值。按照序列创建的术语，这等同于子句 "STARTS WITH"。

- `increment_size`（可选 - 缺省为 `1`）：对序列/表的调用应该区分的值。按照序列创建的术语，这等同于子句 "INCREMENT BY"。

- `force_table_use`（可选 - 缺省为 `false`）：即使方言可能支持序列，是否也应该强制把表用作后台结构。

- `value_column`（可选 - 缺省为 `next_val`）：只和表结构相关，它是用于保存值的字段的名称。

- `optimizer` (optional - defaults to `none`): See 第 5.1.2.3.1 节 “标识符生成器的优化”

新生成器的第二个是 `org.hibernate.id.enhanced.TableGenerator`，它的目的首先是替代 `table` 生成器，即使它实际上比 `org.hibernate.id.MultipleHiLoPerTableGenerator` 功能要强得多；其次，作为利用可插拔 optimizer 的 `org.hibernate.id.MultipleHiLoPerTableGenerator` 的替代品。基本上这个生成器定义了一个可以利用多个不同的键值记录存储大量不同增量值的表。这个生成器有如下的配置参数：

- `table_name`（可选 — 默认是 `hibernate_sequences`）：所用的表的名称。

- `value_column_name`（可选 — 默认为 `next_val`）：用于存储这些值的表的字段的名字。

- `segment_column_name`（可选，默认为 `sequence_name`）：用于保存 "segment key" 的字段的名称。这是标识使用哪个增量值的值。

- `segment_value`（可选，默认为 `default`）：我们为这个生成器获取增量值的 segment 的 "segment key"。

- `segment_value_length`（可选 — 默认为 `255`）：用于 schema 生成；创建 Segment Key 字段的字段大小。

- `initial_value`（可选 — 默认是 `1`）：从表里获取的初始值。

- `increment_size`（可选 — 默认是 `1`）：对表随后的调用应该区分的值。

- `optimizer` (optional - defaults to `??`): See 第 5.1.2.3.1 节 “标识符生成器的优化”.

##### 5.1.2.3.1. 标识符生成器的优化

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 (第 5.1.2.3 节 “增强的标识符生成器” support this operation.

- `none`（如果没有指定 optimizer，通常这是缺省配置）：这不会执行任何优化，在每次请求时都访问数据库。

- `hilo`：对从数据库获取的值应用 hi/lo 算法。用于这个 optimizer 的从数据库获取的值应该是有序的。它们表明“组编号”。`increment_size` 将乘以内存里的值来定义组的“hi 值”。

- `pooled`：和 `hilo` 一样，这个 optimizer 试图最小化对数据库的访问。然而，我们只是简单地把“下一组”的起始值而不是把序列值和分组算法的组合存入到数据库结构里。在这里，`increment_size` 表示数据库里的值。

#### 5.1.2.4. Partial identifier generation

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.

### 5.1.3. Optimistic locking properties (optional)

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.

一个脱管（detached）实例的 version 或 timestamp 属性不能为空（null），因为 Hibernate 不管 `unsaved-value` 被指定为何种策略，它将任何属性为空的 version 或 timestamp 实例看作为瞬时（transient）实例。 避免 Hibernate 中的传递重附（transitive reattachment）问题的一个简单方法是 定义一个不能为空的 version 或 timestamp 属性，特别是在人们使用程序分配的标识符（assigned identifiers） 或复合主键时非常有用。

#### 5.1.3.1. Version number

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|."
    />

| `column`（可选 — 默认为属性名）：指定持有版本号的字段名。
| `name`：持久化类的属性名。
| `type`（可选 — 默认是 `integer`）：版本号的类型。
| `access`（可选 — 默认为 `property`）：Hibernate 用来访问属性值的策略。
| `unsaved-value`（可选 — 默认是 `undefined`）：用于标明某个实例时刚刚被实例化的（尚未保存）版本属性值，依靠这个值就可以把这种情况 和已经在先前的 session 中保存或装载的脱管（detached）实例区分开来。（`undefined` 指明应被使用的标识属性值。）
| `generated`（可选 — 默认是 `never`）：表明此版本属性值是否实际上是由数据库生成的。请参阅 generated properties 部分的讨论。
| `insert`（可选 — 默认是 `true`）：表明此版本列应该包含在 SQL 插入语句中。只有当数据库字段有默认值 `0` 的时候，才可以设置为 `false`。

#### 5.1.3.2. Timestamp

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|."
    />

| `column`（可选 — 默认为属性名）：存有时间戳的字段名。
| `name`：在持久化类中的 JavaBeans 风格的属性名，其 Java 类型是 `Date` 或者 `Timestamp` 的。
| `access`（可选 — 默认为 `property`）：Hibernate 用来访问属性值的策略。
| `unsaved-value`（可选 — 默认是 `null`）：用于标明某个实例时刚刚被实例化的（尚未保存）版本属性值，依靠这个值就可以把这种情况和已经在先前的 session 中保存或装载的脱管（detached）实例区分开来。（`undefined` 指明使用标识属性值进行这种判断。）
| `source`（可选 — 默认是 `vm`）：Hibernate 如何才能获取到时间戳的值呢？从数据库，还是当前 JVM？从数据库获取会带来一些负担，因为 Hibernate 必须访问数据库来获得“下一个值”，但是在集群环境中会更安全些。还要注意，并不是所有的 `Dialect（方言）`都支持获得数据库的当前时间戳的，而支持的数据库中又有一部分因为精度不足，用于锁定是不安全的（例如 Oracle 8）。
| `generated`（可选 - 默认是 `never`）：指出时间戳值是否实际上是由数据库生成的。请参阅 generated properties 的讨论。

## 注意

注意，`<timestamp>` 和 `<version type="timestamp">` 是等价的。并且 `<timestamp source="db">` 和 `<version type="dbtimestamp">` 是等价的。

### 5.1.4. Property

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.

#### 5.1.4.1. Property mapping with annotations

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.

##### 5.1.4.1.1. Type

You can also manually specify a type using the `@org.hibernate.annotations.Type` and some parameters if needed. `@Type.type` could be:

1. Hibernate 基本类型名（比如：`integer, string, character,date, timestamp, float, binary, serializable, object, blob`）。

2. 一个 Java 类的名字，这个类属于一种默认基础类型（比如：`int, float,char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob`)。

3. 一个可以序列化的 Java 类的名字。

4. 一个自定义类型的类的名字。（比如：`com.illflow.type.MyCustomType`)。

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;

        ...

    }

##### 5.1.4.1.2. Access type

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`.

## @org.hibernate.annotations.AccessType

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.

##### 5.1.4.1.3. Optimistic lock

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.

##### 5.1.4.1.4. Declaring column attributes

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

| `name` (optional): the column name (default to the property name)
| `unique` (optional): set a unique constraint on this column or not (default false)
| `nullable` (optional): set the column as nullable (default true).
| `insertable` (optional): whether or not the column will be part of the insert statement (default true)
| `updatable` (optional): whether or not the column will be part of the update statement (default true)
| `columnDefinition` (optional): override the sql DDL fragment for this particular column (non portable)
| `table` (optional): define the targeted table (default primary table)
| ``length`` (optional): column length (default 255)
| ``precision`` (optional): column decimal precision (default 0)
| ``scale`` (optional): column decimal scale if useful (default 0)

##### 5.1.4.1.5. Formula

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.

##### 5.1.4.1.6. Non-annotated property defaults

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`

#### 5.1.4.2. Property mapping with hbm.xml

`<property>` 元素为类定义了一个持久化的、JavaBean 风格的属性。

    <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"
    />

| `name`：属性的名字，以小写字母开头。
| `column`（可选 — 默认为属性名字）：对应的数据库字段名。 也可以通过嵌套的 `<column>` 元素指定。
| `type`（可选）：一个 Hibernate 类型的名字。
| `update, insert`（可选 — 默认为 `true`）： 表明用于`UPDATE` 和/或 `INSERT` 的 SQL 语句中是否包含这个被映射了的字段。这二者如果都设置为 `false` 则表明这是一个“外源性（derived）”的属性，它的值来源于映射到同一个（或多个） 字段的某些其他属性，或者通过一个 trigger（触发器）或其他程序生成。
| `formula`（可选）：一个 SQL 表达式，定义了这个计算 （computed） 属性的值。计算属性没有和它对应的数据库字段。
| `access`（可选 — 默认为 `property`）：Hibernate 用来访问属性值的策略。
| `lazy`（可选 — 默认为 `false`）：指定 指定实例变量第一次被访问时，这个属性是否延迟抓取（fetched lazily）（ 需要运行时字节码增强）。
| `unique`（可选）：使用 DDL 为该字段添加唯一的约束。同样，允许它作为 `property-ref` 引用的目标。
| `not-null`（可选）：使用 DDL 为该字段添加可否为空（nullability）的约束。
| `optimistic-lock`（可选 — 默认为 `true`）：指定这个属性在做更新时是否需要获得乐观锁定（optimistic lock）。换句话说，它决定这个属性发生脏数据时版本（version）的值是否增长。
| `generated`（可选 — 默认为 `never`）：表明此属性值是否实际上是由数据库生成的。请参阅 generated properties 的讨论。

typename 可以是如下几种：

1. Hibernate 基本类型名（比如：`integer, string, character,date, timestamp, float, binary, serializable, object, blob`）。

2. 一个 Java 类的名字，这个类属于一种默认基础类型（比如：`int, float,char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob`)。

3. 一个可以序列化的 Java 类的名字。

4. 一个自定义类型的类的名字。（比如：`com.illflow.type.MyCustomType`)。

如果你没有指定类型，Hibernarte 会使用反射来得到这个名字的属性，以此来猜测正确的 Hibernate 类型。Hibernate 会按照规则 2，3，4 的顺序对属性读取器（getter方法）的返回类进行解释。然而，这还不够。 在某些情况下你仍然需要 `type` 属性。（比如，为了区别`Hibernate.DATE` 和`Hibernate.TIMESTAMP`,或者为了指定一个自定义类型。）

`access` 属性用来让你控制 Hibernate 如何在运行时访问属性。在默认情况下，Hibernate 会使用属性的 get/set 方法对（pair）。如果你指明 `access="field"`，Hibernate 会忽略 get/set 方法对，直接使用反射来访问成员变量。你也可以指定你自己的策略，这就需要你自己实现 `org.hibernate.property.PropertyAccessor` 接口，再在 access 中设置你自定义策略类的名字。

衍生属性（derive propertie）是一个特别强大的特征。这些属性应该定义为只读，属性值在装载时计算生成。 你用一个 SQL 表达式生成计算的结果，它会在这个实例转载时翻译成一个 SQL 查询的 `SELECT` 子查询语句。

    <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 )"/>

注意，你可以使用实体自己的表，而不用为这个特别的列定义别名（上面例子中的 `customerId`）。同时注意，如果你不喜欢使用属性， 你可以使用嵌套的 `<formula>` 映射元素。

### 5.1.5. Embedded objects (aka components)

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>

| `name`：属性名。
| `class`（可选 — 默认为通过反射得到的属性类型）：组件（子）类的名字。
| `insert`：被映射的字段是否出现在 SQL 的 `INSERT` 语句中？
| `update`：被映射的字段是否出现在 SQL 的 `UPDATE` 语句中？
| `access`（可选 — 默认为 `property`）：Hibernate 用来访问属性值的策略。
| `lazy`（可选 — 默认是 `false`）：表明此组件应在实例变量第一次被访问的时候延迟加载（需要编译时字节码装置器）。
| `optimistic-lock`（可选 — 默认是 `true`）：表明更新此组件是否需要获取乐观锁。换句话说，当这个属性变脏时，是否增加版本号（Version）。
| `unique`（可选 — 默认是 `false`）：表明组件映射的所有字段上都有唯一性约束。

其 `<property>` 子标签为子类的一些属性与表字段之间建立映射。

`<component>` 元素允许加入一个 `<parent>` 子元素，在组件类内部就可以有一个指向其容器的实体的反向引用。

The `<dynamic-component>` element allows a `Map` to be mapped as a component, where the property names refer to keys of the map. See 第 9.5 节 “动态组件（Dynamic components）” for more information. This feature is not supported in annotations.

### 5.1.6. Inheritance strategy

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.

#### 5.1.6.1. Single table per class hierarchy strategy

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>

| `name`：子类的全限定名。
| `discriminator-value（辨别标志）`（可选 — 默认为类名）：一个用于区分每个独立的子类的值。
| `proxy`（可选）：指定一个类或者接口，在延迟装载时作为代理使用。
| `lazy`（可选，默认是 `true`）：设置为 `lazy="false"` 禁止使用延迟装载。

For information about inheritance mappings see 第 10 章 继承映射（Inheritance Mapping） .

##### 5.1.6.1.1. 鉴别器（discriminator）

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"
    />

| `column`（可选 — 默认为 `class`）discriminator 器字段的名字。
| `type`（可选 — 默认为 `string`）一个 Hibernate 字段类型的名字
| `force(强制)`（可选 — 默认为 `false`）"强制" Hibernate 指定允许的鉴别器值,即使当取得的所有实例都是根类的。
| `insert`（可选 - 默认为`true`）如果你的鉴别器字段也是映射为复合标识（composite identifier）的一部分，则需将这个值设为 `false`。（告诉 Hibernate 在做 SQL `INSERT` 时不包含该列）
| `formula`（可选）一个 SQL 表达式，在类型判断（判断是父类还是具体子类 — 译注）时执行。可用于基于内容的鉴别器。

鉴别器字段的实际值是根据 `<class>` 和 `<subclass>` 元素中的 `discriminator-value` 属性得来的。

使用 `formula` 属性你可以定义一个 SQL 表达式，用来判断一行数据的类型。

    <discriminator

        formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end"

        type="integer"/>

#### 5.1.6.2. Joined subclass strategy

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>

| `name`：子类的全限定名。
| `table`：子类的表名。
| `proxy`（可选）：指定一个类或者接口，在延迟装载时作为代理使用。
| `lazy`（可选，默认是 `true`）：设置为 `lazy="false"` 禁止使用延迟装载。

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 第 10 章 继承映射（Inheritance Mapping） .

#### 5.1.6.3. Table per class strategy

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>

| `name`：子类的全限定名。
| `table`：子类的表名。
| `proxy`（可选）：指定一个类或者接口，在延迟装载时作为代理使用。
| `lazy`（可选，默认是 `true`）：设置为 `lazy="false"` 禁止使用延迟装载。

这种映射策略不需要指定辨别标志（discriminator）字段。

For information about inheritance mappings see 第 10 章 继承映射（Inheritance Mapping） .

#### 5.1.6.4. Inherit properties from superclasses

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.

#### 5.1.6.5. Mapping one entity to several tables

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>

| `table`：被连接表的名称。
| `schema`（可选）：覆盖在根 `<hibernate-mapping>` 元素中指定的 schema 名字。
| `catalog`（可选）：覆盖在根 `<hibernate-mapping>` 元素中指定的 catalog 名字。
| `fetch`（可选 — 默认是 `join`）：如果设置为默认值 `join`，Hibernate 将使用一个内连接来得到这个类或其超类定义的 `<join>`，而使用一个外连接来得到其子类定义的 `<join>`。如果设置为 `select`，则 Hibernate 将为子类定义的 `<join>` 使用顺序选择。这仅在一行数据表示一个子类的对象的时候才会发生。对这个类和其超类定义的 `<join>`，依然会使用内连接得到。
| `inverse`（可选 — 默认是 `false`）：如果打开，Hibernate 不会插入或者更新此连接定义的属性。
| `optional`（可选 — 默认是 `false`）：如果打开，Hibernate 只会在此连接定义的属性非空时插入一行数据，并且总是使用一个外连接来得到这些属性。

例如，一个人（person）的地址（address）信息可以被映射到单独的表中（并保留所有属性的值类型语义）：

    <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>

        ...

此特性常常对遗留数据模型有用，我们推荐表个数比类个数少，以及细粒度的领域模型。然而，在单独的继承树上切换继承映射策略是有用的，后面会解释这点。

### 5.1.7. Mapping one to one and one to many associations

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.

1. basic operations, which include: `persist, merge, delete, save-update, evict, replicate, lock and refresh`;

2. special values: `delete-orphan` or `all` ;

3. comma-separated combinations of operation names: `cascade="persist,merge,evict"` or `cascade="all,delete-orphan"`. See 第 11.11 节 “传播性持久化（transitive persistence）” for a full explanation. Note that single valued many-to-one associations do not support orphan delete.

By default, single point associations are eagerly fetched in JPA 2. You can mark it as lazily fetched by using `@ManyToOne(fetch=FetchType.LAZY)` in which case Hibernate will proxy the association and load it when the state of the associated entity is reached. You can force Hibernate not to use a proxy by using `@LazyToOne(NO_PROXY)`. In this case, the property is fetched lazily when the instance variable is first accessed. This requires build-time bytecode instrumentation. lazy="false" specifies that the association will always be eagerly fetched.

With the default JPA options, single-ended associations are loaded with a subsequent select if set to `LAZY`, or a SQL JOIN is used for `EAGER` associations. You can however adjust the fetching strategy, ie how data is fetched by using `@Fetch`. `FetchMode` can be `SELECT` (a select is triggered when the association needs to be loaded) or `JOIN` (use a SQL JOIN to load the association while loading the owner entity). `JOIN` overrides any lazy attribute (an association loaded through a `JOIN` strategy cannot be lazy).

#### 5.1.7.1. Using a foreign key or an association table

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.

例 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.

例 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`.

例 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"
    />

| `name`：属性名。
| `column`（可选）：外键字段的名称。也可以通过嵌套的 `<column>` 指定。
| `class`（可选 — 默认是通过反射得到的属性类型）：被关联的类的名字。
| `cascade（级联）`（可选）表明操作是否从父对象级联到被关联的对象。
| `fetch`（可选 — 默认为 `select`）：在外连接抓取（outer-join fetching）和序列选择抓取（sequential select fetching）两者中选择其一。
| `update, insert`（可选 — 默认为 `true`）指定对应的字段是否包含在用于 `UPDATE` 和/或 `INSERT` 的 SQL 语句中。如果二者都是`false`,则这是一个纯粹的 “外源性（derived）”关联，它的值是通过映射到同一个（或多个）字段的某些其他属性得到 或者通过 trigger（触发器）、或其他程序生成。
| `property-ref`：（可选）被关联到此外键的类中的对应属性的名字。如果没有指定，被关联类的主键将被使用。
| `access`（可选 — 默认为 `property`）：Hibernate 用来访问属性值的策略。
| `unique`（可选）：使用 DDL 为外键字段生成一个唯一约束。此外， 这也可以用作 `property-ref` 的目标属性。这使关联同时具有一对一的效果。
| `not-null`（可选）：使用 DDL 为外键字段生成一个非空约束。
| `optimistic-lock`（可选 — 默认为 `true`）：指定这个属性在做更新时是否需要获得乐观锁定（optimistic lock）。换句话说，它决定这个属性发生脏数据时版本（version）的值是否增长。
| `lazy`（可选 — 默认为 `proxy`）：默认情况下，单点关联是经过代理的。`lazy="no-proxy"` 指定此属性应该在实例变量第一次被访问时应该延迟抓取（fetche lazily）（需要运行时字节码的增强）。`lazy="false"` 指定此关联总是被预先抓取。
| `not-found`（可选 - 默认为`exception`）：指定如何处理引用缺失行的外键：`ignore` 会把缺失的行作为一个空关联处理。
| `entity-name`（可选）：被关联的类的实体名。
| `formula`（可选）：SQL 表达式，用于定义 computed（计算出的）外键值。

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 第 11.11 节 “传播性持久化（transitive persistence）” for a full explanation. Note that single valued, many-to-one and one-to-one, associations do not support orphan delete.

一个典型的简单 `many-to-one` 定义例子：

    <many-to-one name="product" class="Product" column="PRODUCT_ID"/>

`property-ref` 属性只应该用来对付遗留下来的数据库系统，可能有外键指向对方关联表的是个非主键字段（但是应该是一个惟一关键字）的情况下。这是一种十分丑陋的关系模型。比如说，假设 `Product` 类有一个惟一的序列号，它并不是主键。（`unique` 属性控制 Hibernate 通过 SchemaExport 工具进行的 DDL 生成。）

    <property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>

那么关于 `OrderItem` 的映射可能是：

    <many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>

当然，我们决不鼓励这种用法。

如果被引用的唯一主键由关联实体的多个属性组成，你应该在名称为 `<properties>` 的元素 里面映射所有关联的属性。

假若被引用的唯一主键是组件的属性，你可以指定属性路径：

    <many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>

#### 5.1.7.2. Sharing the primary key with the associated entity

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.

例 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"
    />

| `name`：属性名。
| `class`（可选 — 默认是通过反射得到的属性类型）：被关联的类的名字。
| `cascade（级联）`（可选）表明操作是否从父对象级联到被关联的对象。
| `constrained（约束）`（可选）表明该类对应的表对应的数据库表，和被关联的对象所对应的数据库表之间，通过一个外键引用对主键进行约束。这个选项影响 `save()` 和 `delete()` 在级联执行时的先后顺序以及决定该关联能否被委托（也在 schema export tool 中被使用）。
| `fetch`（可选 — 默认为 `select`）：在外连接抓取（outer-join fetching）和序列选择抓取（sequential select fetching）两者中选择其一。
| `property-ref`：（可选）指定关联类的属性名，这个属性将会和本类的主键相对应。如果没有指定，会使用对方关联类的主键。
| `access`（可选 — 默认为 `property`）：Hibernate 用来访问属性值的策略。
| `formula` （可选）：绝大多数一对一的关联都指向其实体的主键。在一些少见的情况中，你可能会指向其他的一个或多个字段，或者是一个表达式，这些情况下，你可以用一个 SQL 公式来表示。（可以在 org.hibernate.test.onetooneformula 找到例子）
| `lazy`（可选 — 默认为 `proxy`）：默认情况下，单点关联是经过代理的。`lazy="no-proxy"`指定此属性应该在实例变量第一次被访问时应该延迟抓取（fetche lazily）（需要运行时字节码的增强）。 `lazy="false"`指定此关联总是被预先抓取。注意，如果`constrained="false"`, 不可能使用代理，Hibernate会采取预先抓取。
| `entity-name`（可选）：被关联的类的实体名。

主键关联不需要额外的表字段；如果两行是通过这种一对一关系相关联的，那么这两行就共享同样的主关键字值。所以如果你希望两个对象通过主键一对一关联，你必须确认它们被赋予同样的标识值。

比如说，对下面的 `Employee` 和 `Person` 进行主键一对一关联：

    <one-to-one name="person" class="Person"/>

    <one-to-one name="employee" class="Employee" constrained="true"/>

现在我们必须确保 PERSON 和 EMPLOYEE 中相关的字段是相等的。我们使用一个被成为 `foreign` 的特殊的 hibernate 标识符生成策略：

    <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>

一个刚刚保存的 `Person` 实例被赋予和该 `Person` 的 `employee` 属性所指向的 `Employee` 实例同样的关键字值。

### 5.1.8. 自然 ID（natural-id）

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>

我们强烈建议你实现 `equals()` 和 `hashCode()` 方法,来比较实体的自然键属性。

这一映射不是为了把自然键作为主键而准备的。

- `mutable`（可选，默认为 `false`）：默认情况下，自然标识属性被假定为不可变的（常量）。

### 5.1.9. Any

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>

| `name`：属性名
| `id-type`：标识符类型
| `meta-type`（可选 -默认是 `string`）：允许辨别标志(discriminator)映射的任何类型。
| `cascade`（可选 — 默认是`none`）：级联的类型。
| `access`（可选 — 默认为 `property`）：Hibernate 用来访问属性值的策略。
| `optimistic-lock`（可选 — 默认是 `true`）：表明更新此组件是否需要获取乐观锁。换句话说，当这个属性变脏时，是否增加版本号（Version）。

### 5.1.10. 属性（Properties）

`<properties>` 元素允许定义一个命名的逻辑分组（grouping）包含一个类中的多个属性。这个元素最重要的用处是允许多个属性的组合作为 `property-ref` 的目标（target）。这也是定义多字段唯一约束的一种方便途径。例如：

    <properties
            name="logicalName"
            insert="true|false"
            update="true|false"
            optimistic-lock="true|false"
            unique="true|false"
    >

            <property ...../>
            <many-to-one .... />
            ........
    </properties>

| `name`：分组的逻辑名称 — 不是 实际属性的名称。
| `insert`：被映射的字段是否出现在 SQL 的 `INSERT` 语句中？
| `update`：被映射的字段是否出现在 SQL 的 `UPDATE` 语句中？
| `optimistic-lock`（可选 — 默认是 `true`）：表明更新此组件是否需要获取乐观锁。换句话说，当这个属性变脏时，是否增加版本号（Version）。
| `unique`（可选 — 默认是 `false`）：表明组件映射的所有字段上都有唯一性约束。

例如，如果我们有如下的 `<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>

然后，我们可能有一些遗留的数据关联，引用 `Person` 表的这个唯一键，而不是主键：

    <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

    }

我们并不推荐这样使用，除非在映射遗留数据的情况下。

### 5.1.11. Some hbm.xml specificities

The hbm.xml structure has some specificities naturally not present when using annotations, let's describe them briefly.

#### 5.1.11.1. Doctype

所有的 XML 映射都需要定义如上所示的 doctype。DTD 可以从上述 URL 中获取，也可以从 `hibernate-x.x.x/src/org/hibernate` 目录中、或 `hibernate.jar` 文件中找到。Hibernate 总是会首先在它的 classptah 中搜索 DTD 文件。如果你发现它是通过连接 Internet 查找 DTD 文件，就对照你的 classpath 目录检查 XML 文件里的 DTD 声明。

##### 5.1.11.1.1. EntityResolver

Hibernate 首先试图在其 classpath 中解析 DTD。这是依靠在系统中注册的 `org.xml.sax.EntityResolver` 的一个具体实现，SAXReader 依靠它来读取 xml 文件。这个自定义的 `EntityResolver` 能辨认两种不同的 systenId 命名空间：

- 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.

- 若 resolver 遇到了一个使用 `classpath://` URL 协议的 systemId，它会辨认出这是 `user namespace`，resolver 试图通过（1) 当前线程上下文的 classloader 和（2) 加载 Hibernate class 的 classloader 来查找这些实体。

下面是一个使用用户命名空间（user namespace）的例子：

    <?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>

这里的 `types.xml` 是 `your.domain` 包中的一个资源，它包含了一个自定义的 typedef。

#### 5.1.11.2. Hibernate-mapping

这个元素包括一些可选的属性。`schema` 和 `catalog` 属性， 指明了这个映射所连接（refer）的表所在的 schema 和/或 catalog 名称。假若指定了这个属性，表名会加上所指定的 schema 和 catalog 的名字扩展为全限定名。假若没有指定，表名就不会使用全限定名。`default-cascade` 指定了未明确注明 `cascade` 属性的 Java 属性和 集合类 Hibernate 会采取什么样的默认级联风格。`auto-import` 属性默认让我们在查询语言中可以使用非全限定名的类名。

    <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"
     />

| `schema`（可选）：数据库 schema 的名称。
| `catalog`（可选）：数据库 catalog 的名称。
| `default-cascade`（可选 — 默认为 `none`）：默认的级联风格。
| `default-access`（可选 — 默认为 `property`）：Hibernate 用来访问所有属性的策略。可以通过实现 `PropertyAccessor` 接口自定义。
| `default-lazy`（可选 — 默认为 `true`）：指定了未明确注明 `lazy` 属性的 Java 属性和集合类，Hibernate 会采取什么样的默认加载风格。
| `auto-import`（可选 — 默认为 `true`）：指定我们是否可以在查询语言中使用非全限定的类名（仅限于本映射文件中的类）。
| `package`（可选）：指定一个包前缀，如果在映射文档中没有指定全限定的类名，就使用这个作为包名。

假若你有两个持久化类，它们的非全限定名是一样的（就是两个类的名字一样，所在的包不一样 — 译者注），你应该设置 `auto-import="false"`。如果你把一个“导入过”的名字同时对应两个类，Hibernate 会抛出一个异常。

注意 `hibernate-mapping` 元素允许你嵌套多个如上所示的 `<class>` 映射。但是最好的做法（也许一些工具需要的）是一个持久化类（或一个类的继承层次）对应一个映射文件，并以持久化的超类名称命名，例如：`Cat.hbm.xml`、`Dog.hbm.xml`，或者如果使用继承，`Animal.hbm.xml`。

#### 5.1.11.3. Key

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"
    />

| `column`（可选）：外键字段的名称。也可以通过嵌套的 `<column>` 指定。
| `on-delete`（可选，默认是 `noaction`）：表明外键关联是否打开数据库级别的级联删除。
| `property-ref`（可选）：表明外键引用的字段不是原表的主键（提供给遗留数据）。
| `not-null`（可选）：表明外键的字段不可为空（这意味着无论何时外键都是主键的一部分）。
| `update`（可选）：表明外键决不应该被更新（这意味着无论何时外键都是主键的一部分）。
| `unique`（可选）：表明外键应有唯一性约束（这意味着无论何时外键都是主键的一部分）。

对那些看重删除性能的系统，我们推荐所有的键都应该定义为 `on-delete="cascade"`，这样 Hibernate 将使用数据库级的 `ON CASCADE DELETE` 约束，而不是多个 `DELETE` 语句。注意，这个特性会绕过 Hibernate 通常对版本数据（versioned data）采用的乐观锁策略。

`not-null` 和 `update` 属性在映射单向一对多关联的时候有用。如果你映射一个单向一对多关联到非空的（non-nullable）外键，你必须 用 `<key not-null="true">` 定义此键字段。

#### 5.1.11.4. 引用（import）

假设你的应用程序有两个同样名字的持久化类，但是你不想在 Hibernate 查询中使用他们的全限定名。除了依赖 `auto-import="true"` 以外，类也可以被显式地“import（引用）”。你甚至可以引用没有被明确映射的类和接口。

    <import class="java.lang.Object" rename="Universe"/>

    <import
            class="ClassName"
            rename="ShortName"
    />

| `class`：任何 Java 类的全限定名。
| `rename`（可选 — 默认为类的全限定名）：在查询语句中可以使用的名字。

## 注意

This feature is unique to hbm.xml and is not supported in annotations.

#### 5.1.11.5. 字段和规则元素（column and formula elements）

任何接受 `column` 属性的映射元素都可以选择接受 `<column>` 子元素。同样的，`formula` 子元素也可以替换 `<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>

`column` 上的大多数属性都提供了在自动模式生成过程中对 DDL 进行裁剪的方法。`read` 和 `write` 属性允许你指定 Hibernate 用于访问字段值的自定义的 SQL。关于更多的内容，请参考 column read and write expressions。

`column` 和 `formula` 属性甚至可以在同一个属性或关联映射中被合并来表达，例如，一些奇异的连接条件。

    <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>

## 5.2. Hibernate 的类型

### 5.2.1. 实体（Entities）和值（values）

和持久化服务相比，Java 级别的对象分为两个组别：

实体entity 独立于任何持有实体引用的对象。与通常的 Java 模型相比，不再被引用的对象会被当作垃圾收集掉。实体必须被显式的保存和删除（除非保存和删除是从父实体向子实体引发的级联）。这和 ODMG 模型中关于对象通过可触及保持持久性有一些不同 — 比较起来更加接近应用程序对象通常在一个大系统中的使用方法。实体支持循环引用和交叉引用，它们也可以加上版本信息。

一个实体的持久状态包含指向其他实体和值类型实例的引用。值可以是原始类型，集合（不是集合中的对象），组件或者特定的不可变对象。与实体不同，值（特别是集合和组件）是通过可触及性来进行持久化和删除的。因为值对象（和原始类型数据）是随着包含他们的实体而被持久化和删除的，他们不能被独立的加上版本信息。值没有独立的标识，所以他们不能被两个实体或者集合共享。

直到现在，我们都一直使用术语“持久类”（persistent class）来代表实体。我们仍然会这么做。然而严格说来，不是所有的用户自定义的，带有持久化状态的类都是实体。组件就是用户自定义类，却是值语义的。`java.lang.String` 类型的 java 属性也是值语义的。给了这个定义以后，我们可以说所有 JDK 提供的类型（类）都是值类型的语义，而用于自定义类型可能被映射为实体类型或值类型语义。采用哪种类型的语义取决于开发人员。在领域模型中，寻找实体类的一个好线索是共享引用指向这个类的单一实例，而组合或聚合通常被转化为值类型。

我们会在本文档中重复碰到这两个概念。

挑战在于将 java 类型系统(和开发者定义的实体和值类型)映射到 SQL/数据库类型系统。Hibernate 提供了连接两个系统之间的桥梁：对于实体类型，我们使用 `<class>`，`<subclass>` 等等。对于值类型，我们使用 `<property>`，`<component>` 及其他，通常跟随着 `type` 属性。这个属性的值是Hibernate 的映射类型的名字。Hibernate 提供了许多现成的映射（标准的 JDK 值类型）。你也可以编写自己的映射类型并实现自定义的变换策略，随后我们会看到这点。

所有的 Hibernate 内建类型，除了 collections 以外，都支持空（null）语义。

### 5.2.2. 基本值类型

内置的 basic mapping types 可以大致地分类为：

`integer, long, short, float, double, character, byte, boolean, yes_no, true_false`

  这些类型都对应 Java 的原始类型或者其封装类，来符合（特定厂商的）SQL 字段类型。`boolean, yes_no` 和 `true_false` 都是 Java 中 `boolean` 或者 `java.lang.Boolean` 的另外说法。

`string`

  从 `java.lang.String` 到 `VARCHAR`（或者 Oracle 的 `VARCHAR2`）的映射。

`date, time, timestamp`

  从 `java.util.Date` 和其子类到 SQL 类型 `DATE`，`TIME` 和 `TIMESTAMP`（或等价类型）的映射。

`calendar, calendar_date`

  从 `java.util.Calendar` 到 SQL 类型 `TIMESTAMP` 和 `DATE`（或等价类型）的映射。

`big_decimal, big_integer`

  从 `java.math.BigDecimal` 和 `java.math.BigInteger` 到 `NUMERIC`（或者 Oracle 的 `NUMBER`类型）的映射。

`locale, timezone, currency`

  从 `java.util.Locale`，`java.util.TimeZone` 和 `java.util.Currency` 到 `VARCHAR`（或者 Oracle 的 `VARCHAR2` 类型）的映射。`Locale` 和 `Currency` 的实例被映射为它们的 ISO 代码。`TimeZone` 的实例被影射为它的 `ID`。

`class`

  从 `java.lang.Class` 到 `VARCHAR`（或者 Oracle 的 `VARCHAR2` 类型）的映射。`Class` 被映射为它的全限定名。

`binary`

  把字节数组（byte arrays）映射为对应的 SQL 二进制类型。

`text`

  Maps long Java strings to a SQL `LONGVARCHAR` or `TEXT` type.

`image`

  Maps long byte arrays to a SQL `LONGVARBINARY`.

`serializable`

  把可序列化的 Java 类型映射到对应的 SQL 二进制类型。你也可以为一个并非默认为基本类型的可序列化 Java 类或者接口指定 Hibernate 类型 `serializable`。

`clob, blob`

  JDBC 类 `java.sql.Clob` 和 `java.sql.Blob`的映射。某些程序可能不适合使用这个类型，因为 blob 和 clob 对象可能在一个事务之外是无法重用的。（而且, 驱动程序对这种类型的支持充满着补丁和前后矛盾。）

`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`

  一般来说，映射类型被假定为是可变的 Java 类型，只有对不可变 Java 类型，Hibernate 会采取特定的优化措施，应用程序会把这些对象作为不可变对象处理。比如，你不应该对作为 `imm_timestamp` 映射的 Date 执行 `Date.setTime()`。要改变属性的值，并且保存这一改变，应用程序必须对这一属性重新设置一个新的（不一样的）对象。

实体及其集合的唯一标识可以是除了 `binary`、 `blob` 和 `clob` 之外的任何基础类型。（联合标识也是允许的，后面会说到。）

在 `org.hibernate.Hibernate` 中，定义了基础类型对应的 `Type` 常量。比如，`Hibernate.STRING` 代表 `string` 类型。

### 5.2.3. 自定义值类型

开发者创建属于他们自己的值类型也是很容易的。比如说，你可能希望持久化 `java.lang.BigInteger` 类型的属性，持久化成为 `VARCHAR` 字段。Hibernate没有内置这样一种类型。自定义类型能够映射一个属性(或集合元素)到不止一个数据库表字段。比如说，你可能有这样的 Java 属性：`getName()`/`setName()`，这是 `java.lang.String` 类型的，对应的持久化到三个字段：`FIRST_NAME`，`INITIAL`，`SURNAME`。

要实现一个自定义类型，可以实现 `org.hibernate.UserType` 或 `org.hibernate.CompositeUserType` 中的任一个，并且使用类型的 Java 全限定类名来定义属性。请查看 `org.hibernate.test.DoubleStringType` 这个例子，看看它是怎么做的。

    <property name="twoStrings" type="org.hibernate.test.DoubleStringType">

        <column name="first_string"/>

        <column name="second_string"/>

    </property>

注意使用 `<column>` 标签来把一个属性映射到多个字段的做法。

`CompositeUserType`，`EnhancedUserType`，`UserCollectionType` 和 `UserVersionType` 接口为更特殊的使用方式提供支持。

你甚至可以在一个映射文件中提供参数给一个 `UserType`。 为了这样做，你的 `UserType` 必须实现 `org.hibernate.usertype.ParameterizedType` 接口。为了给自定义类型提供参数，你可以在映射文件中使用 `<type>` 元素。

    <property name="priority">

        <type name="com.mycompany.usertypes.DefaultValueIntegerType">

            <param name="default">0</param>

        </type>

    </property>

现在，`UserType` 可以从传入的 `Properties` 对象中得到 `default` 参数的值。

如果你非常频繁地使用某一 `UserType`，可以为他定义一个简称。这可以通过使用 `<typedef>` 元素来实现。Typedefs 为一自定义类型赋予一个名称，并且如果此类型是参数化的，还可以包含一系列默认的参数值。

    <typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero">

        <param name="default">0</param>

    </typedef>

    <property name="priority" type="default_zero"/>

也可以根据具体案例通过属性映射中的类型参数覆盖在 typedef 中提供的参数。

尽管 Hibernate 内建的丰富的类型和对组件的支持意味着你可能很少 需要使用自定义类型。不过，为那些在你的应用中经常出现的(非实体)类使用自定义类型也是一个好方法。例如，一个 `MonetaryAmount` 类使用 `CompositeUserType` 来映射是不错的选择，虽然他可以很容易地被映射成组件。这样做的动机之一是抽象。使用自定义类型，以后假若你改变表示金额的方法时，它可以保证映射文件不需要修改。

## 5.3. 多次映射同一个类

对特定的持久化类，映射多次是允许的。这种情形下，你必须指定 entity name 来区别不同映射实体的对象实例。（默认情况下，实体名字和类名是相同的。） Hibernate 在操作持久化对象、编写查询条件，或者把关联映射到指定实体时，允许你指定这个 entity name（实体名字）。

    <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>

注意这里关联是如何用 `entity-name` 来代替 `class` 的。

## 注意

This feature is not supported in Annotations

## 5.4. SQL 中引号包围的标识符

你可通过在映射文档中使用反向引号（`）把表名或者字段名包围起来，以强制 Hibernate 在生成的 SQL 中把标识符用引号包围起来。Hibernate 会使用相应的 SQL`Dialect`（方言）来使用正确的引号风格(通常是双引号，但是在 SQL Server 中是括号，MySQL 中是反向引号)。

    @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>

## 5.5. 数据库生成属性（Generated Properties）

Generated properties 指的是其值由数据库生成的属性。一般来说，如果对象有任何属性由数据库生成值，Hibernate 应用程序需要进行`刷新（refresh）`。但如果把属性标明为 generated，就可以转由 Hibernate 来负责这个动作。实际上。对定义了 generated properties 的实体,每当 Hibernate 执行一条 SQL INSERT 或者 UPDATE 语句，会立刻执行一条 select 来获得生成的值。

被标明为 generated 的属性还必须是 non-insertable 和 non-updateable 的。只有 versions、timestamps 和 simple properties 可以被标明为 generated。

`never`（默认）标明此属性值不是从数据库中生成。

`insert` — 标明此属性值在 insert 的时候生成，但是不会在随后的 update 时重新生成。比如说创建日期就归属于这类。注意虽然 version 和 timestamp 属性可以被标注为 generated，但是不适用这个选项。

`always` — 标明此属性值在 insert 和 update 时都会被生成。

To mark a property as generated, use `@Generated`.

## 5.6. Column transformers: read and write expressions

Hibernate allows you to customize the SQL it uses to read and write the values of columns mapped to simple properties. For example, if your database provides a set of data encryption functions, you can invoke them for individual columns like this:

    @Entity

    class CreditCard {

       @Column(name="credit_card_num")

       @ColumnTransformer(

          read="decrypt(credit_card_num)",

          write="encrypt(?)")

       public String getCreditCardNumber() { return creditCardNumber; }

       public void setCreditCardNumber(String number) { this.creditCardNumber = number; }

       private String creditCardNumber;

    }

or in XML

    <property name="creditCardNumber">

            <column

              name="credit_card_num"

              read="decrypt(credit_card_num)"

              write="encrypt(?)"/>

    </property>

## 注意

You can use the plural form `@ColumnTransformers` if more than one columns need to define either of these rules.

If a property uses more that one column, you must use the `forColumn` attribute to specify which column, the expressions are targeting.

    @Entity

    class User {

       @Type(type="com.acme.type.CreditCardType")

       @Columns( {

          @Column(name="credit_card_num"),

          @Column(name="exp_date") } )

       @ColumnTransformer(

          forColumn="credit_card_num",

          read="decrypt(credit_card_num)",

          write="encrypt(?)")

       public CreditCard getCreditCard() { return creditCard; }

       public void setCreditCard(CreditCard card) { this.creditCard = card; }

       private CreditCard creditCard;

    }

每当属性在查询里被引用时，Hibernate 都自动应用自定义的表达式。这种功能和 derived-property `formula` 相似，但有两个不同的地方：

- 属性由一个或多个属性组成，它作为自动模式生成的一部分导出。

- 属性是可读写的，非只读的。

如果指定了 `write` 表达式，它必须只包含一个“?”占位符。

## 5.7. 辅助数据库对象（Auxiliary Database Objects）

允许 CREATE 和 DROP 任意数据库对象，与 Hibernate 的 schema 交互工具组合起来，可以提供在 Hibernate 映射文件中完全定义用户 schema 的能力。虽然这是为创建和销毁 trigger（触发器）或stored procedure（存储过程）等特别设计的，实际上任何可以在 `java.sql.Statement.execute()` 方法中执行的 SQL 命令都可以在此使用（比如ALTER, INSERT，等等）。本质上有两种模式来定义辅助数据库对象...

第一种模式是在映射文件中显式声明 CREATE 和 DROP 命令：

    <hibernate-mapping>

        ...

        <database-object>

            <create>CREATE TRIGGER my_trigger ...</create>

            <drop>DROP TRIGGER my_trigger</drop>

        </database-object>

    </hibernate-mapping>

第二种模式是提供一个类，这个类知道如何组织 CREATE 和 DROP 命令。这个特别类必须实现 `org.hibernate.mapping.AuxiliaryDatabaseObject` 接口。

    <hibernate-mapping>

        ...

        <database-object>

            <definition class="MyTriggerDefinition"/>

        </database-object>

    </hibernate-mapping>

还有，这些数据库对象可以特别指定为仅在特定的方言中才使用。

    <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

版权 © 2004 Red Hat, Inc.

- 上一页第 4 章 持久化类（Persistent Classes）
- 上一级
- 起始页
- 下一页第 6 章 Types