diff --git a/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml b/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml
index 20ae700f9f..3fd1eda171 100644
--- a/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml
+++ b/documentation/manual/src/main/docbook/en-US/content/basic_mapping.xml
@@ -429,13 +429,6 @@ public class Flight implements Serializable {
@org.hibernate.annotations.Entity:
-
- mutable (defaults to true): Immutable
- classes, mutable=false, cannot be updated or
- deleted by the application. This allows Hibernate to make some minor
- performance optimizations.
-
-
dynamicInsert /
dynamicUpdate (defaults to false): specifies that
@@ -535,6 +528,11 @@ public class Flight implements Serializable {
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
@@ -548,7 +546,7 @@ public class Flight implements Serializable {
@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).
+ 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
@@ -828,13 +826,24 @@ public class Summary {
- id
+ 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.
- The <id> element defines the mapping from that
- property to the primary key column.
+ 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.
@@ -896,11 +905,446 @@ public class Summary {
that the class has no identifier property.
The unsaved-value attribute is almost never
- needed in Hibernate3.
+ needed in Hibernate3 and indeed has no corresponding element in
+ annotations.
- There is an alternative <composite-id>
- declaration that allows access to legacy data with composite keys. Its
- use is strongly discouraged for anything else.
+ 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.
+
+
+ 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.
+
+
+ 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;
+}
+
+@Entity
+class User {
+ @EmbeddedId UserId id;
+ Integer age;
+}
+
+@Embeddable
+class UserId implements Serializable {
+ String firstName;
+ String lastName;
+}
+
+ 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).
+
+ 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;
+}
+
+@Entity
+class User {
+ @EmbeddedId UserId id;
+ Integer age;
+}
+
+@Embeddable
+class UserId implements Serializable {
+ String firstName;
+ String lastName;
+}
+
+ 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"/>
+
+ <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>
+
+
+
+ Multiple @Id properties
+
+ XXXXXXXXXXXXXXXXXXXXXXXXXXXXX
+
+ Another, arguably more natural, approach is to place
+ @Id on multiple properties of my entity. This
+ approach is only supported by Hibernate 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;
+}
+
+@Entity
+class User {
+ @EmbeddedId UserId id;
+ Integer age;
+}
+
+@Embeddable
+class UserId implements Serializable {
+ String firstName;
+ String lastName;
+}
+
+ In this case Customer being it's own
+ identifier representation, it must implement
+ Serializable.
+
+
+
+ @IdClass
+
+ @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
+class Customer {
+ @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;
+}
+
+@Entity
+class User {
+ @EmbeddedId UserId id;
+ Integer age;
+}
+
+@Embeddable
+class UserId implements Serializable {
+ String firstName;
+ String lastName;
+}
+
+ Customer and
+ CustomerId do have the same properties
+ customerNumber as well as
+ user.
+
+ While not JPA standard, Hibernate let's you declare the
+ vanilla associated property in the
+ @IdClass.
+
+ @Entity
+class Customer {
+ @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;
+}
+
+@Entity
+class User {
+ @EmbeddedId UserId id;
+ Integer age;
+}
+
+@Embeddable
+class UserId implements Serializable {
+ String firstName;
+ String lastName;
+}
+
+
+
+ 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.
+
+