Author: epbernard
Date: 2010-03-02 17:39:12 -0500 (Tue, 02 Mar 2010)
New Revision: 18915
Modified:
core/trunk/annotations/src/main/docbook/en/modules/entity.xml
core/trunk/annotations/src/main/java/org/hibernate/annotations/AccessType.java
core/trunk/annotations/src/main/java/org/hibernate/annotations/CascadeType.java
core/trunk/annotations/src/main/java/org/hibernate/annotations/CollectionOfElements.java
core/trunk/annotations/src/main/java/org/hibernate/annotations/IndexColumn.java
Log:
HHH-4933 deprecate legacy annotations, document @ElementCollection, reorganize collection
description, remove legacy annotations documentation when a new one is in place
Modified: core/trunk/annotations/src/main/docbook/en/modules/entity.xml
===================================================================
--- core/trunk/annotations/src/main/docbook/en/modules/entity.xml 2010-03-02 12:01:59 UTC
(rev 18914)
+++ core/trunk/annotations/src/main/docbook/en/modules/entity.xml 2010-03-02 22:39:12 UTC
(rev 18915)
@@ -60,9 +60,8 @@
<section id="entity-mapping-entity">
<title>Marking a POJO as persistent entity</title>
- <para>Every persistent POJO class is an entity bean and is declared
- using the <literal>@Entity</literal> annotation (at the class
- level):</para>
+ <para>Every persistent POJO class is an entity and is declared using the
+ <literal>@Entity</literal> annotation (at the class
level):</para>
<programlisting>@Entity
public class Flight implements Serializable {
@@ -74,11 +73,11 @@
public void setId(Long id) { this.id = id; }
} </programlisting>
- <para><literal>@Entity</literal> declares the class as an entity
bean
- (i.e. a persistent POJO class), <literal>@Id</literal> declares the
- identifier property of this entity bean. The other mapping declarations
- are implicit. The class Flight is mapped to the Flight table, using the
- column id as its primary key column.</para>
+ <para><literal>@Entity</literal> declares the class as an entity
(i.e. a
+ persistent POJO class), <literal>@Id</literal> declares the identifier
+ property of this entity. The other mapping declarations are implicit.
+ The class Flight is mapped to the Flight table, using the column id as
+ its primary key column.</para>
<note>
<para>The concept of configuration by exception is central to the JPA
@@ -100,8 +99,8 @@
<para><literal>@Table</literal> is set at the class level; it
allows
you to define the table, catalog, and schema names for your entity
- bean mapping. If no <literal>@Table</literal> is defined the default
- values are used: the unqualified class name of the entity.</para>
+ mapping. If no <literal>@Table</literal> is defined the default
values
+ are used: the unqualified class name of the entity.</para>
<programlisting>@Entity
@Table(name="tbl_sky")
@@ -140,8 +139,8 @@
<section id="entity-mapping-entity-version"
revision="1">
<title>Versioning for optimistic locking</title>
- <para>You can add optimistic locking capability to an entity bean
- using the <literal>@Version</literal> annotation:</para>
+ <para>You can add optimistic locking capability to an entity using the
+ <literal>@Version</literal> annotation:</para>
<programlisting>@Entity
public class Flight implements Serializable {
@@ -176,12 +175,12 @@
<title>Declaring basic property mappings</title>
<para>Every non static non transient property (field or method
- depending on the access type) of an entity bean is considered
- persistent, unless you annotate it as <literal>@Transient</literal>.
- Not having an annotation for your property is equivalent to the
- appropriate <literal>@Basic</literal> annotation. The
- <literal>@Basic</literal> annotation allows you to declare the
- fetching strategy for a property:</para>
+ depending on the access type) of an entity is considered persistent,
+ unless you annotate it as <literal>@Transient</literal>. Not having
an
+ annotation for your property is equivalent to the appropriate
+ <literal>@Basic</literal> annotation. The
<literal>@Basic</literal>
+ annotation allows you to declare the fetching strategy for a
+ property:</para>
<programlisting>public transient int counter; //transient property
@@ -568,7 +567,7 @@
entity (note that you can override that using the
<literal>@Access</literal> annotation).</para>
- <para>The <literal>Person</literal> entity bean has two
component
+ <para>The <literal>Person</literal> entity has two component
properties, <literal>homeAddress</literal> and
<literal>bornIn</literal>. <literal>homeAddress</literal>
property has
not been annotated, but Hibernate will guess that it is a persistent
@@ -654,9 +653,9 @@
<title>Mapping identifier properties</title>
<para>The <literal>@Id</literal> annotation lets you define
which
- property is the identifier of your entity bean. This property can be set
- by the application itself or be generated by Hibernate (preferred). You
- can define the identifier generation strategy thanks to the
+ property is the identifier of your entity. This property can be set by
+ the application itself or be generated by Hibernate (preferred). You can
+ define the identifier generation strategy thanks to the
<literal>@GeneratedValue</literal> annotation.</para>
<section>
@@ -1404,7 +1403,7 @@
<section>
<title>One-to-one</title>
- <para>You can associate entity beans through a one-to-one relationship
+ <para>You can associate entities through a one-to-one relationship
using <literal>@OneToOne</literal>. There are three cases for
one-to-one associations: either the associated entities share the same
primary keys values, a foreign key is held by one of the entities
@@ -1496,8 +1495,7 @@
<para>The third possibility (using an association table) is quite
exotic.</para>
- <programlisting>
-@Entity
+ <programlisting>@Entity
public class Customer implements Serializable {
@OneToOne(cascade = CascadeType.ALL)
<emphasis role="bold">@JoinTable(name =
"CustomerPassports",
@@ -1513,8 +1511,7 @@
@OneToOne(<emphasis role="bold">mappedBy =
"passport"</emphasis>)
public Customer getOwner() {
...
-}
- </programlisting>
+} </programlisting>
<para>A <classname>Customer</classname> is linked to a
<classname>Passport</classname> through a association table named
@@ -1601,21 +1598,393 @@
<section id="entity-mapping-association-collections"
revision="1">
<title>Collections</title>
+ <para>You can map <classname>Collection</classname>,
+ <classname>List</classname>, <classname>Map</classname>
and
+ <classname>Set</classname> pointing to associated entities as
+ one-to-many or many-to-many associations using the
+ <classname>@OneToMany</classname> or
+ <classname>@ManyToMany</classname> annotation respectively. If the
+ collection is of a basic type or of an embeddable type, use
+ <classname>@ElementCollection</classname>. We will describe that in
+ more detail in the following subsections.</para>
+
+ <section id="entity-mapping-association-collection-onetomany"
+ revision="2">
+ <title>One-to-many</title>
+
+ <para>One-to-many associations are declared at the property level
+ with the annotation <literal>@OneToMany</literal>. One to many
+ associations may be bidirectional.</para>
+
+ <section>
+ <title>Bidirectional</title>
+
+ <para>Since many to one are (almost) always the owner side of a
+ bidirectional relationship in the JPA spec, the one to many
+ association is annotated by
+ <literal>@OneToMany(mappedBy=...)</literal></para>
+
+ <programlisting>@Entity
+public class Troop {
+ @OneToMany(mappedBy="troop")
+ public Set<Soldier> getSoldiers() {
+ ...
+}
+
+@Entity
+public class Soldier {
+ @ManyToOne
+ @JoinColumn(name="troop_fk")
+ public Troop getTroop() {
+ ...
+} </programlisting>
+
+ <para><classname>Troop</classname> has a bidirectional one
to many
+ relationship with <literal>Soldier</literal> through the
+ <literal>troop</literal> property. You don't have to (must
not)
+ define any physical mapping in the <literal>mappedBy</literal>
+ side.</para>
+
+ <para>To map a bidirectional one to many, with the one-to-many
+ side as the owning side, you have to remove the
+ <literal>mappedBy</literal> element and set the many to one
+ <literal>@JoinColumn</literal> as insertable and updatable to
+ false. This solution is not optimized and will produce some
+ additional UPDATE statements.</para>
+
+ <programlisting>@Entity
+public class Troop {
+ @OneToMany
+ @JoinColumn(name="troop_fk") //we need to duplicate the physical
information
+ public Set<Soldier> getSoldiers() {
+ ...
+}
+
+@Entity
+public class Soldier {
+ @ManyToOne
+ @JoinColumn(name="troop_fk", insertable=false, updatable=false)
+ public Troop getTroop() {
+ ...
+}</programlisting>
+ </section>
+
+ <section>
+ <title>Unidirectional</title>
+
+ <para>A unidirectional one to many using a foreign key column in
+ the owned entity is not that common and not really recommended. We
+ strongly advise you to use a join table for this kind of
+ association (as explained in the next section). This kind of
+ association is described through a
+ <literal>@JoinColumn</literal></para>
+
+ <programlisting>@Entity
+public class Customer implements Serializable {
+ @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
+ @JoinColumn(name="CUST_ID")
+ public Set<Ticket> getTickets() {
+ ...
+}
+
+@Entity
+public class Ticket implements Serializable {
+ ... //no bidir
+} </programlisting>
+
+ <para><literal>Customer</literal> describes a
unidirectional
+ relationship with <literal>Ticket</literal> using the join
column
+ <literal>CUST_ID</literal>.</para>
+ </section>
+
+ <section>
+ <title>Unidirectional with join table</title>
+
+ <para>A unidirectional one to many with join table is much
+ preferred. This association is described through an
+ <literal>(a)JoinTable</literal>.</para>
+
+ <programlisting>@Entity
+public class Trainer {
+ @OneToMany
+ @JoinTable(
+ name="TrainedMonkeys",
+ joinColumns = @JoinColumn( name="trainer_id"),
+ inverseJoinColumns = @JoinColumn( name="monkey_id")
+ )
+ public Set<Monkey> getTrainedMonkeys() {
+ ...
+}
+
+@Entity
+public class Monkey {
+ ... //no bidir
+} </programlisting>
+
+ <para><literal>Trainer</literal> describes a
unidirectional
+ relationship with <classname>Monkey</classname> using the join
+ table <classname>TrainedMonkeys</classname>, with a foreign key
+ <literal>trainer_id</literal> to
<literal>Trainer</literal>
+ (<literal>joinColumns</literal>) and a foreign key
+ <literal>monkey_id</literal> to
<literal>Monkey</literal>
+ (<literal>inversejoinColumns</literal>).</para>
+ </section>
+
+ <section
id="entity-mapping-association-collection-manytomany-default"
+ revision="1">
+ <title>Defaults</title>
+
+ <para>Without describing any physical mapping, a unidirectional
+ one to many with join table is used. The table name is the
+ concatenation of the owner table name, <keycap>_</keycap>, and
the
+ other side table name. The foreign key name(s) referencing the
+ owner table is the concatenation of the owner table,
+ <keycap>_</keycap>, and the owner primary key column(s) name.
The
+ foreign key name(s) referencing the other side is the
+ concatenation of the owner property name, <keycap>_</keycap>,
and
+ the other side primary key column(s) name. A unique constraint is
+ added to the foreign key referencing the other side table to
+ reflect the one to many.</para>
+
+ <programlisting>@Entity
+public class Trainer {
+ @OneToMany
+ public Set<Tiger> getTrainedTigers() {
+ ...
+}
+
+@Entity
+public class Tiger {
+ ... //no bidir
+} </programlisting>
+
+ <para><classname>Trainer</classname> describes a
unidirectional
+ relationship with <classname>Tiger</classname> using the join
+ table <literal>Trainer_Tiger</literal>, with a foreign key
+ <literal>trainer_id</literal> to
<literal>Trainer</literal> (table
+ name, <keycap>_</keycap>, trainer id) and a foreign key
+ <literal>trainedTigers_id</literal> to
<literal>Monkey</literal>
+ (property name, <keycap>_</keycap>, Tiger primary
column).</para>
+ </section>
+ </section>
+
+ <section id="eentity-mapping-association-collection-manytomany"
+ revision="">
+ <title>Many-to-many</title>
+
+ <section>
+ <title>Definition</title>
+
+ <para>A many-to-many association is defined logically using the
+ <literal>@ManyToMany</literal> annotation. You also have to
+ describe the association table and the join conditions using the
+ <literal>@JoinTable</literal> annotation. If the association is
+ bidirectional, one side has to be the owner and one side has to be
+ the inverse end (ie. it will be ignored when updating the
+ relationship values in the association table):</para>
+
+ <programlisting>@Entity
+public class Employer implements Serializable {
+ @ManyToMany(
+ targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,
+ cascade={CascadeType.PERSIST, CascadeType.MERGE}
+ )
+ @JoinTable(
+ name="EMPLOYER_EMPLOYEE",
+ joinColumns=@JoinColumn(name="EMPER_ID"),
+ inverseJoinColumns=@JoinColumn(name="EMPEE_ID")
+ )
+ public Collection getEmployees() {
+ return employees;
+ }
+ ...
+} </programlisting>
+
+ <programlisting>@Entity
+public class Employee implements Serializable {
+ @ManyToMany(
+ cascade = {CascadeType.PERSIST, CascadeType.MERGE},
+ mappedBy = "employees",
+ targetEntity = Employer.class
+ )
+ public Collection getEmployers() {
+ return employers;
+ }
+} </programlisting>
+
+ <para>We've already shown the many declarations and the detailed
+ attributes for associations. We'll go deeper in the
+ <literal>@JoinTable</literal> description, it defines a
+ <literal>name</literal>, an array of join columns (an array in
+ annotation is defined using { A, B, C }), and an array of inverse
+ join columns. The latter ones are the columns of the association
+ table which refer to the <classname>Employee</classname> primary
+ key (the "other side").</para>
+
+ <para>As seen previously, the other side don't have to (must not)
+ describe the physical mapping: a simple
+ <literal>mappedBy</literal> argument containing the owner side
+ property name bind the two.</para>
+ </section>
+
+ <section>
+ <title>Default values</title>
+
+ <para>As any other annotations, most values are guessed in a many
+ to many relationship. Without describing any physical mapping in a
+ unidirectional many to many the following rules applied. The table
+ name is the concatenation of the owner table name,
+ <keycap>_</keycap> and the other side table name. The foreign
key
+ name(s) referencing the owner table is the concatenation of the
+ owner table name, <keycap>_</keycap> and the owner primary key
+ column(s). The foreign key name(s) referencing the other side is
+ the concatenation of the owner property name,
<keycap>_</keycap>,
+ and the other side primary key column(s). These are the same rules
+ used for a unidirectional one to many relationship.</para>
+
+ <programlisting>
+@Entity
+public class Store {
+ @ManyToMany(cascade = CascadeType.PERSIST)
+ public Set<City> getImplantedIn() {
+ ...
+ }
+}
+
+@Entity
+public class City {
+ ... //no bidirectional relationship
+}
+ </programlisting>
+
+ <para>A <literal>Store_City</literal> is used as the join
table.
+ The <literal>Store_id</literal> column is a foreign key to the
+ <literal>Store</literal> table. The
+ <literal>implantedIn_id</literal> column is a foreign key to the
+ <literal>City</literal> table.</para>
+
+ <para>Without describing any physical mapping in a bidirectional
+ many to many the following rules applied. The table name is the
+ concatenation of the owner table name, <keycap>_</keycap> and
the
+ other side table name. The foreign key name(s) referencing the
+ owner table is the concatenation of the other side property name,
+ <keycap>_</keycap>, and the owner primary key column(s). The
+ foreign key name(s) referencing the other side is the
+ concatenation of the owner property name, <keycap>_</keycap>,
and
+ the other side primary key column(s). These are the same rules
+ used for a unidirectional one to many relationship.</para>
+
+ <programlisting>@Entity
+public class Store {
+ @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
+ public Set<Customer> getCustomers() {
+ ...
+ }
+}
+
+@Entity
+public class Customer {
+ @ManyToMany(mappedBy="customers")
+ public Set<Store> getStores() {
+ ...
+ }
+} </programlisting>
+
+ <para>A <literal>Store_Customer</literal> is used as the
join
+ table. The <literal>stores_id</literal> column is a foreign key
to
+ the <literal>Store</literal> table. The
+ <literal>customers_id</literal> column is a foreign key to the
+ <literal>Customer</literal> table.</para>
+ </section>
+ </section>
+
+ <section>
+ <title>Collection of basic types or embeddable objects</title>
+
+ <para>In some simple situation, do don't need to associate two
+ entities but simply create a collection of basic types or embeddable
+ objects. Use the <classname>@ElementCollection</classname> in this
+ case.</para>
+
+ <programlisting>@Entity
+public class User {
+ [...]
+ public String getLastname() { ...}
+
+ @ElementCollection
+ @CollectionTable(name="Nicknames",
joinColumns=@JoinColumn(name="user_id"))
+ @Column(name="nickname")
+ public Set<String> getNicknames() { ... }
+}</programlisting>
+
+ <para>The collection table holding the collection data is set using
+ the <classname>@CollectionTable</classname> annotation. If omitted
+ the collection table name default to the concatenation of the name
+ of the containing entity and the name of the collection attribute,
+ separated by an underscore: in our example, it would be
+ <literal>User_nicknames</literal>.</para>
+
+ <para>The column holding the basic type is set using the
+ <classname>@Column</classname> annotation. If omitted, the column
+ name defaults to the property name: in our example, it would be
+ <literal>nicknames</literal>.</para>
+
+ <para>But you are not limited to basic types, the collection type
+ can be any embeddable object. To override the columns of the
+ embeddable object in the collection table, use the
+ <classname>@AttributeOverride</classname> annotation.</para>
+
+ <programlisting>@Entity
+public class User {
+ [...]
+ public String getLastname() { ...}
+
+ @ElementCollection
+ @CollectionTable(name="Addresses",
joinColumns=@JoinColumn(name="user_id"))
+ @AttributeOverrides({
+ @AttributeOverride(name="street1",
column=@Column(name="fld_street"))
+ })
+ public Set<Address> getAddresses() { ... }
+}
+
+@Embeddable
+public class Address {
+ public String getStreet1() {...}
+ [...]
+}</programlisting>
+
+ <para>Such an embeddable object cannot contains a collection
+ itself.</para>
+
+ <note>
+ <para>in <classname>@AttributeOverride</classname>, you
must use
+ the <literal>value.</literal> prefix to override properties of
the
+ embeddable object used in the map value and the
+ <literal>key.</literal> prefix to override properties of the
+ embeddable object used in the map key.</para>
+
+ <programlisting>@Entity
+public class User {
+ @ElementCollection
+ @AttributeOverrides({
+ @AttributeOverride(name="key.street1",
column=@Column(name="fld_street")),
+ @AttributeOverride(name="value.stars",
column=@Column(name="fld_note"))
+ })
+ public Map<Address,Rating> getFavHomes() { ... }
</programlisting>
+ </note>
+
+ <note>
+ <para>We recommend you to migrate from
+
<classname>(a)org.hibernate.annotations.CollectionOfElements</classname>
+ to the new <classname>@ElementCollection</classname>
+ annotation.</para>
+ </note>
+ </section>
+
<section id="entity-mapping-association-collections-overview"
revision="1">
- <title>Overview</title>
+ <title>Indexed collections (List, Map)</title>
- <para>You can map <classname>Collection</classname>,
- <classname>List</classname>, <classname>Map</classname>
and
- <classname>Set</classname> pointing to associated entities as
- one-to-many or many-to-many associations using the
- <classname>@OneToMany</classname> or
- <classname>@ManyToMany</classname> annotation respectively. If the
- collection is of a basic type or of an embeddable type, use
- <classname>@ElementCollection</classname>. We will describe that
in
- more detail in the following subsections but let's first focus on
- some semantic differences between the various collections.</para>
-
<para>Lists can be mapped in two different ways:</para>
<itemizedlist>
@@ -1864,6 +2233,13 @@
| customer_id | | orders_number |
|-------------| |---------------|</programlisting>
+ <note>
+ <para>We recommend you to migrate from
+ <classname>(a)org.hibernate.annotations.MapKey</classname> /
+
<classname>(a)org.hibernate.annotation.MapKeyManyToMany</classname>
+ to the new standard approach described above.</para>
+ </note>
+
<para>Let's now explore the various collection semantics based on
the mapping you are choosing.</para>
@@ -1946,308 +2322,6 @@
<para>More support for collections are available via Hibernate
specific extensions (see <xref linkend="entity-hibspec"
/>).</para>
</section>
-
- <section id="entity-mapping-association-collection-onetomany"
- revision="2">
- <title>One-to-many</title>
-
- <para>One-to-many associations are declared at the property level
- with the annotation <literal>@OneToMany</literal>. One to many
- associations may be bidirectional.</para>
-
- <section>
- <title>Bidirectional</title>
-
- <para>Since many to one are (almost) always the owner side of a
- bidirectional relationship in the EJB3 spec, the one to many
- association is annotated by <literal>@OneToMany( mappedBy=...
- )</literal></para>
-
- <programlisting>@Entity
-public class Troop {
- @OneToMany(mappedBy="troop")
- public Set<Soldier> getSoldiers() {
- ...
-}
-
-@Entity
-public class Soldier {
- @ManyToOne
- @JoinColumn(name="troop_fk")
- public Troop getTroop() {
- ...
-} </programlisting>
-
- <para><classname>Troop</classname> has a bidirectional one
to many
- relationship with <literal>Soldier</literal> through the
- <literal>troop</literal> property. You don't have to (must
not)
- define any physical mapping in the <literal>mappedBy</literal>
- side.</para>
-
- <para>To map a bidirectional one to many, with the one-to-many
- side as the owning side, you have to remove the
- <literal>mappedBy</literal> element and set the many to one
- <literal>@JoinColumn</literal> as insertable and updatable to
- false. This solution is obviously not optimized and will produce
- some additional UPDATE statements.</para>
-
- <programlisting>@Entity
-public class Troop {
- @OneToMany
- @JoinColumn(name="troop_fk") //we need to duplicate the physical
information
- public Set<Soldier> getSoldiers() {
- ...
-}
-
-@Entity
-public class Soldier {
- @ManyToOne
- @JoinColumn(name="troop_fk", insertable=false, updatable=false)
- public Troop getTroop() {
- ...
-}</programlisting>
- </section>
-
- <section>
- <title>Unidirectional</title>
-
- <para>A unidirectional one to many using a foreign key column in
- the owned entity is not that common and not really recommended. We
- strongly advise you to use a join table for this kind of
- association (as explained in the next section). This kind of
- association is described through a
- <literal>@JoinColumn</literal></para>
-
- <programlisting>
-@Entity
-public class Customer implements Serializable {
- @OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
- @JoinColumn(name="CUST_ID")
- public Set<Ticket> getTickets() {
- ...
-}
-
-@Entity
-public class Ticket implements Serializable {
- ... //no bidir
-}
- </programlisting>
-
- <para><literal>Customer</literal> describes a
unidirectional
- relationship with <literal>Ticket</literal> using the join
column
- <literal>CUST_ID</literal>.</para>
- </section>
-
- <section>
- <title>Unidirectional with join table</title>
-
- <para>A unidirectional one to many with join table is much
- preferred. This association is described through an
- <literal>(a)JoinTable</literal>.</para>
-
- <programlisting>
-@Entity
-public class Trainer {
- @OneToMany
- @JoinTable(
- name="TrainedMonkeys",
- joinColumns = @JoinColumn( name="trainer_id"),
- inverseJoinColumns = @JoinColumn( name="monkey_id")
- )
- public Set<Monkey> getTrainedMonkeys() {
- ...
-}
-
-@Entity
-public class Monkey {
- ... //no bidir
-}
- </programlisting>
-
- <para><literal>Trainer</literal> describes a
unidirectional
- relationship with <classname>Monkey</classname> using the join
- table <classname>TrainedMonkeys</classname>, with a foreign key
- <literal>trainer_id</literal> to
<literal>Trainer</literal>
- (<literal>joinColumns</literal>) and a foreign key
- <literal>monkey_id</literal> to
<literal>Monkey</literal>
- (<literal>inversejoinColumns</literal>).</para>
- </section>
-
- <section
id="entity-mapping-association-collection-manytomany-default"
- revision="1">
- <title>Defaults</title>
-
- <para>Without describing any physical mapping, a unidirectional
- one to many with join table is used. The table name is the
- concatenation of the owner table name, <keycap>_</keycap>, and
the
- other side table name. The foreign key name(s) referencing the
- owner table is the concatenation of the owner table,
- <keycap>_</keycap>, and the owner primary key column(s) name.
The
- foreign key name(s) referencing the other side is the
- concatenation of the owner property name, <keycap>_</keycap>,
and
- the other side primary key column(s) name. A unique constraint is
- added to the foreign key referencing the other side table to
- reflect the one to many.</para>
-
- <programlisting>
-@Entity
-public class Trainer {
- @OneToMany
- public Set<Tiger> getTrainedTigers() {
- ...
-}
-
-@Entity
-public class Tiger {
- ... //no bidir
-}
- </programlisting>
-
- <para><classname>Trainer</classname> describes a
unidirectional
- relationship with <classname>Tiger</classname> using the join
- table <literal>Trainer_Tiger</literal>, with a foreign key
- <literal>trainer_id</literal> to
<literal>Trainer</literal> (table
- name, <keycap>_</keycap>, trainer id) and a foreign key
- <literal>trainedTigers_id</literal> to
<literal>Monkey</literal>
- (property name, <keycap>_</keycap>, Tiger primary
column).</para>
- </section>
- </section>
-
- <section id="eentity-mapping-association-collection-manytomany"
- revision="">
- <title>Many-to-many</title>
-
- <section>
- <title>Definition</title>
-
- <para>A many-to-many association is defined logically using the
- <literal>@ManyToMany</literal> annotation. You also have to
- describe the association table and the join conditions using the
- <literal>@JoinTable</literal> annotation. If the association is
- bidirectional, one side has to be the owner and one side has to be
- the inverse end (ie. it will be ignored when updating the
- relationship values in the association table):</para>
-
- <programlisting>
-@Entity
-public class Employer implements Serializable {
- @ManyToMany(
- targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,
- cascade={CascadeType.PERSIST, CascadeType.MERGE}
- )
- @JoinTable(
- name="EMPLOYER_EMPLOYEE",
- joinColumns=@JoinColumn(name="EMPER_ID"),
- inverseJoinColumns=@JoinColumn(name="EMPEE_ID")
- )
- public Collection getEmployees() {
- return employees;
- }
- ...
-}
- </programlisting>
-
- <programlisting>
-@Entity
-public class Employee implements Serializable {
- @ManyToMany(
- cascade = {CascadeType.PERSIST, CascadeType.MERGE},
- mappedBy = "employees",
- targetEntity = Employer.class
- )
- public Collection getEmployers() {
- return employers;
- }
-}
- </programlisting>
-
- <para>We've already shown the many declarations and the detailed
- attributes for associations. We'll go deeper in the
- <literal>@JoinTable</literal> description, it defines a
- <literal>name</literal>, an array of join columns (an array in
- annotation is defined using { A, B, C }), and an array of inverse
- join columns. The latter ones are the columns of the association
- table which refer to the <classname>Employee</classname> primary
- key (the "other side").</para>
-
- <para>As seen previously, the other side don't have to (must not)
- describe the physical mapping: a simple
- <literal>mappedBy</literal> argument containing the owner side
- property name bind the two.</para>
- </section>
-
- <section>
- <title>Default values</title>
-
- <para>As any other annotations, most values are guessed in a many
- to many relationship. Without describing any physical mapping in a
- unidirectional many to many the following rules applied. The table
- name is the concatenation of the owner table name,
- <keycap>_</keycap> and the other side table name. The foreign
key
- name(s) referencing the owner table is the concatenation of the
- owner table name, <keycap>_</keycap> and the owner primary key
- column(s). The foreign key name(s) referencing the other side is
- the concatenation of the owner property name,
<keycap>_</keycap>,
- and the other side primary key column(s). These are the same rules
- used for a unidirectional one to many relationship.</para>
-
- <programlisting>
-@Entity
-public class Store {
- @ManyToMany(cascade = CascadeType.PERSIST)
- public Set<City> getImplantedIn() {
- ...
- }
-}
-
-@Entity
-public class City {
- ... //no bidirectional relationship
-}
- </programlisting>
-
- <para>A <literal>Store_City</literal> is used as the join
table.
- The <literal>Store_id</literal> column is a foreign key to the
- <literal>Store</literal> table. The
- <literal>implantedIn_id</literal> column is a foreign key to the
- <literal>City</literal> table.</para>
-
- <para>Without describing any physical mapping in a bidirectional
- many to many the following rules applied. The table name is the
- concatenation of the owner table name, <keycap>_</keycap> and
the
- other side table name. The foreign key name(s) referencing the
- owner table is the concatenation of the other side property name,
- <keycap>_</keycap>, and the owner primary key column(s). The
- foreign key name(s) referencing the other side is the
- concatenation of the owner property name, <keycap>_</keycap>,
and
- the other side primary key column(s). These are the same rules
- used for a unidirectional one to many relationship.</para>
-
- <programlisting>
-@Entity
-public class Store {
- @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
- public Set<Customer> getCustomers() {
- ...
- }
-}
-
-@Entity
-public class Customer {
- @ManyToMany(mappedBy="customers")
- public Set<Store> getStores() {
- ...
- }
-}
- </programlisting>
-
- <para>A <literal>Store_Customer</literal> is used as the
join
- table. The <literal>stores_id</literal> column is a foreign key
to
- the <literal>Store</literal> table. The
- <literal>customers_id</literal> column is a foreign key to the
- <literal>Customer</literal> table.</para>
- </section>
- </section>
</section>
<section id="entity-mapping-association-cascade">
@@ -2255,36 +2329,41 @@
<para>You probably have noticed the <literal>cascade</literal>
attribute taking an array of <classname>CascadeType</classname> as a
- value. The cascade concept in EJB3 is very is similar to the
- transitive persistence and cascading of operations in Hibernate, but
- with slightly different semantics and cascading types:</para>
+ value. The cascade concept in JPA is very is similar to the transitive
+ persistence and cascading of operations in Hibernate, but with
+ slightly different semantics and cascading types:</para>
<itemizedlist>
<listitem>
- <para>CascadeType.PERSIST: cascades the persist (create) operation
- to associated entities persist() is called or if the entity is
- managed</para>
+ <para><literal>CascadeType.PERSIST</literal>: cascades the
persist
+ (create) operation to associated entities persist() is called or
+ if the entity is managed</para>
</listitem>
<listitem>
- <para>CascadeType.MERGE: cascades the merge operation to
- associated entities if merge() is called or if the entity is
- managed</para>
+ <para><literal>CascadeType.MERGE</literal>: cascades the
merge
+ operation to associated entities if merge() is called or if the
+ entity is managed</para>
</listitem>
<listitem>
- <para>CascadeType.REMOVE: cascades the remove operation to
- associated entities if delete() is called</para>
+ <para><literal>CascadeType.REMOVE</literal>: cascades the
remove
+ operation to associated entities if delete() is called</para>
</listitem>
<listitem>
- <para>CascadeType.REFRESH: cascades the refresh operation to
- associated entities if refresh() is called</para>
+ <para><literal>CascadeType.REFRESH:</literal> cascades the
refresh
+ operation to associated entities if refresh() is called</para>
</listitem>
<listitem>
- <para>CascadeType.ALL: all of the above</para>
+ <para><literal>CascadeType.DETACH:</literal> cascades the
detach
+ operation to associated entities if detach() is called</para>
</listitem>
+
+ <listitem>
+ <para><literal>CascadeType.ALL</literal>: all of the
above</para>
+ </listitem>
</itemizedlist>
<note>
@@ -2293,8 +2372,30 @@
linkend="entity-hibspec-cascade" /> for more
information</para>
</note>
- <para>Please refer to the chapter 6.3 of the EJB3 specification for
+ <para>Please refer to the chapter 6.3 of the JPA specification for
more information on cascading and create/merge semantics.</para>
+
+ <para>You can also enable the orphan removal semantic. If an entity is
+ removed from a <classname>@OneToMany</classname> collection or an
+ associated entity is dereferenced from a
+ <classname>@OneToOne</classname> association, this associated entity
+ can be marked for deletion if <literal>orphanRemoval</literal> is
set
+ to true. In a way, it means that the associated entity's lifecycle is
+ bound to the owning entity just like an embeddable object is.</para>
+
+ <programlisting>@Entity class Customer {
+ @OneToMany(orphanRemoval=true) public Set<Order> getOrders() { return
orders; }
+ public void setOrders(Set<Order> orders) { this.orders = orders; }
+ private Set<Order> orders;
+
+ [...]
+}
+
+@Entity class Order { ... }
+
+Customer customer = em.get(Customer.class, 1l);
+Order order = em.get(Order.class, 1l);
+customer.getOrders().remove(order); //order will be deleted by
cascade</programlisting>
</section>
<section id="entity-mapping-association-fetching"
revision="1">
@@ -2313,9 +2414,9 @@
<literal>EAGER</literal>. For more information about static
fetching,
check <xref linkend="entity-hibspec-singleassoc-fetching"
/>.</para>
- <para>The recommanded approach is to use
<literal>LAZY</literal> onn
+ <para>The recommanded approach is to use
<literal>LAZY</literal> on
all static fetching definitions and override this choice dynamically
- through JPA-QL. JPA-QL has a <literal>fetch</literal> keyword that
+ through JP-QL. JP-QL has a <literal>fetch</literal> keyword that
allows you to override laziness when doing a particular query. This is
very useful to improve performance and is decided on a use case to use
case basis.</para>
@@ -2323,7 +2424,8 @@
</section>
<section>
- <title>Mapping composite primary and foreign keys</title>
+ <title>Mapping composite primary keys and foreign keys to composite
+ primary keys</title>
<para>Composite primary keys use a embedded class as the primary key
representation, so you'd use the <literal>@Id</literal> and
@@ -2331,11 +2433,10 @@
the <literal>@EmbeddedId</literal> annotation. Note that the dependent
class has to be serializable and implements
<methodname>equals()</methodname>/<methodname>hashCode()</methodname>.
- You can also use <literal>@IdClass</literal> as described in <xref
- linkend="entity-mapping-identifier" />.</para>
+ You can also use <literal>@IdClass</literal>. These are more detailed
in
+ <xref linkend="entity-mapping-identifier" />.</para>
- <programlisting>
-@Entity
+ <programlisting>@Entity
public class RegionalArticle implements Serializable {
@Id
@@ -2343,21 +2444,18 @@
}
@Embeddable
-public class RegionalArticlePk implements Serializable { ... }
- </programlisting>
+public class RegionalArticlePk implements Serializable { ... }
</programlisting>
<para>or alternatively</para>
- <programlisting>
-@Entity
+ <programlisting>@Entity
public class RegionalArticle implements Serializable {
@EmbeddedId
public RegionalArticlePk getPk() { ... }
}
-public class RegionalArticlePk implements Serializable { ... }
- </programlisting>
+public class RegionalArticlePk implements Serializable { ... }
</programlisting>
<para><literal>@Embeddable</literal> inherit the access type of
its
owning entity unless <literal>@Access</literal> is used. Composite
@@ -2368,8 +2466,7 @@
explicitly. Otherwise, Hibernate will suppose that you use the same
order of columns as in the primary key declaration.</para>
- <programlisting>
-@Entity
+ <programlisting>@Entity
public class Parent implements Serializable {
@Id
public ParentPk id;
@@ -2383,11 +2480,9 @@
})
public Set<Child> children; //unidirectional
...
-}
- </programlisting>
+} </programlisting>
- <programlisting>
-@Entity
+ <programlisting>@Entity
public class Child implements Serializable {
@Id @GeneratedValue
public Integer id;
@@ -2399,17 +2494,14 @@
@JoinColumn(name="parentFirstName", referencedColumnName =
"firstName")
})
public Parent parent; //unidirectional
-}
- </programlisting>
+} </programlisting>
- <programlisting>
-@Embeddable
+ <programlisting>@Embeddable
public class ParentPk implements Serializable {
String firstName;
String lastName;
...
-}
- </programlisting>
+} </programlisting>
<para>Note the explicit usage of the
<literal>referencedColumnName</literal>.</para>
@@ -2418,15 +2510,14 @@
<section>
<title>Mapping secondary tables</title>
- <para>You can map a single entity bean to several tables using the
+ <para>You can map a single entity to several tables using the
<literal>@SecondaryTable</literal> or
<literal>@SecondaryTables</literal> class level annotations. To
express
that a column is in a particular table, use the
<literal>table</literal>
parameter of <literal>@Column</literal> or
<literal>(a)JoinColumn</literal>.</para>
- <programlisting>
-@Entity
+ <programlisting>@Entity
@Table(name="MainCat")
<emphasis role="bold">@SecondaryTables({
@SecondaryTable(name="Cat1", pkJoinColumns={
@@ -2459,7 +2550,7 @@
public String getStoryPart2() {
return storyPart2;
}
-</programlisting>
+}</programlisting>
<para>In this example, <literal>name</literal> will be in
<literal>MainCat</literal>. <literal>storyPart1</literal>
will be in
@@ -2479,16 +2570,33 @@
<section id="entity-mapping-query">
<title>Mapping Queries</title>
+ <para>While you can write queries in your code, it is considered a good
+ practice to externalize them:</para>
+
+ <itemizedlist>
+ <listitem>
+ <para>it make developer/DBA communications easier</para>
+ </listitem>
+
+ <listitem>
+ <para>named queries are pre-compiled by Hibernate at startup
+ time</para>
+ </listitem>
+ </itemizedlist>
+
+ <para>Unfortunately, you lose the type-safety of queries written using the
+ Criteria API.</para>
+
<section id="entity-mapping-query-hql" label="Mapping JPAQL/HQL
queries"
revision="1">
- <title>Mapping JPAQL/HQL queries</title>
+ <title>Mapping JP-QL/HQL queries</title>
- <para>You can map EJBQL/HQL queries using annotations.
+ <para>You can map JP-QL/HQL queries using annotations.
<literal>@NamedQuery</literal> and
<literal>@NamedQueries</literal> can
- be defined at the class level or in a JPA XML file. However their
- definitions are global to the session factory/entity manager factory
- scope. A named query is defined by its name and the actual query
- string.</para>
+ be defined at the class level or in a JPA XML deployment descriptor.
+ However their definitions are global to the session factory/entity
+ manager factory scope. A named query is defined by its name and the
+ actual query string.</para>
<programlisting><entity-mappings>
<named-query name="plane.getAll">
@@ -2512,14 +2620,13 @@
...
}
...
-}
- </programlisting>
+} </programlisting>
<para>You can also provide some hints to a query through an array of
<literal>QueryHint</literal> through a
<literal>hints</literal>
attribute.</para>
- <para>The availabe Hibernate hints are</para>
+ <para>The available Hibernate hints are</para>
<para></para>
@@ -2592,6 +2699,11 @@
</tbody>
</tgroup>
</table>
+
+ <para>You can also define the lock mode by which the returned entities
+ should be locked using the <literal>lockMode</literal> property. This
is
+ equivalent to the optional lock mode of the entitymanager lookup
+ operations.</para>
</section>
<section id="entity-mapping-query-native" revision="2">
@@ -2618,10 +2730,10 @@
<para><programlisting>@NamedNativeQuery(name="night&area",
query="select night.id nid, night.night_duration, "
+ " night.night_date, area.id aid, night.area_id, area.name "
- + "from Night night, Area area where night.area_id = area.id",
<emphasis
-
role="bold">resultSetMapping="joinMapping"</emphasis>)
+ + "from Night night, Area area where night.area_id = area.id",
+ <emphasis
role="bold">resultSetMapping="joinMapping"</emphasis>)
@SqlResultSetMapping(name="joinMapping", entities={
- @EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class, fields =
{
+ @EntityResult(entityClass=Night.class, fields = {
@FieldResult(name="id", column="nid"),
@FieldResult(name="duration", column="night_duration"),
@FieldResult(name="date", column="night_date"),
@@ -2643,8 +2755,11 @@
see an implicit declaration of the property / column.</para>
<programlisting>@Entity
-<emphasis role="bold">@SqlResultSetMapping(name="implicit",
entities=(a)EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class))
-@NamedNativeQuery(name="implicitSample", query="select * from
SpaceShip", resultSetMapping="implicit")</emphasis>
+<emphasis role="bold">@SqlResultSetMapping(name="implicit",
+ entities=(a)EntityResult(entityClass=SpaceShip.class))
+@NamedNativeQuery(name="implicitSample",
+ query="select * from SpaceShip",
+ resultSetMapping="implicit")</emphasis>
public class SpaceShip {
private String name;
private String model;
@@ -2689,7 +2804,7 @@
<programlisting>@Entity
@SqlResultSetMapping(name="compositekey",
-
entities=(a)EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class,
+ entities=(a)EntityResult(entityClass=SpaceShip.class,
fields = {
@FieldResult(name="name", column = "name"),
@FieldResult(name="model", column = "model"),
@@ -2786,13 +2901,6 @@
}
</programlisting>
- <note>
- <para>If you look at the dimension property, you'll see that Hibernate
- supports the dotted notation for embedded objects (you can even have
- nested embedded objects). EJB3 implementations do not have to support
- this feature, we do :-)</para>
- </note>
-
<para>If you retrieve a single entity and if you use the default
mapping, you can use the <literal>resultClass</literal> attribute
instead of <literal>resultSetMapping</literal>:</para>
@@ -3136,25 +3244,21 @@
Place your annotations before the package declaration.</para>
</note>
- <programlisting>
-@TypeDef(
- name = "phoneNumber",
- defaultForType = PhoneNumber.class,
- typeClass = PhoneNumberType.class
+ <programlisting>@TypeDef(
+ name = "phoneNumber",
+ defaultForType = PhoneNumber.class,
+ typeClass = PhoneNumberType.class
)
@Entity
public class ContactDetails {
- ...
- private PhoneNumber localPhoneNumber;
- @Type(type="phoneNumber")
- private OverseasPhoneNumber overseasPhoneNumber;
- ...
-}
+ [...]
+ private PhoneNumber localPhoneNumber;
+ @Type(type="phoneNumber")
+ private OverseasPhoneNumber overseasPhoneNumber;
+ [...]
+}</programlisting>
-
-</programlisting>
-
<para>The following example shows the usage of the
<literal>parameters</literal> attribute to customize the
TypeDef.</para>
@@ -3178,8 +3282,7 @@
@Type(type="caster")
public String getSmallText() {
...
-}
- </programlisting>
+} </programlisting>
<para>When using composite user type, you will have to express column
definitions. The <literal>@Columns</literal> has been introduced for
@@ -3248,7 +3351,8 @@
<programlisting>@Entity
public class Antenna {
@Id public Integer id;
- @Generated(GenerationTime.ALWAYS) @Column(insertable = false, updatable = false)
+ @Generated(GenerationTime.ALWAYS)
+ @Column(insertable = false, updatable = false)
public String longitude;
@Generated(GenerationTime.INSERT) @Column(insertable = false)
@@ -3257,10 +3361,11 @@
<para>Annotate your property as <literal>@Generated</literal>
You have
to make sure your insertability or updatability does not conflict with
- the generation strategy you have chosen. When GenerationTime.INSERT is
- chosen, the property must not contains insertable columns, when
- GenerationTime.ALWAYS is chosen, the property must not contains
- insertable nor updatable columns.</para>
+ the generation strategy you have chosen. When
+ <literal>GenerationTime.INSERT</literal> is chosen, the property
must
+ not contains insertable columns, when
+ <literal>GenerationTime.ALWAYS</literal> is chosen, the property
must
+ not contains insertable nor updatable columns.</para>
<para><literal>@Version</literal> properties cannot be
<literal>@Generated(INSERT)</literal> by design, it has to be either
@@ -3282,8 +3387,6 @@
public Owner getOwner() {
return owner;
}</programlisting>
-
- <para></para>
</section>
<section>
@@ -3394,7 +3497,7 @@
<section id="entity-hibspec-singleassoc-fetching">
<title>Lazy options and fetching modes</title>
- <para>EJB3 comes with the <literal>fetch</literal> option to
define
+ <para>JPA comes with the <literal>fetch</literal> option to
define
lazy loading and fetching modes, however Hibernate has a much more
option set in this area. To fine tune the lazy loading and fetching
strategies, some additional annotations have been introduced:</para>
@@ -3503,10 +3606,11 @@
mapping (polymorphic) associations. You should use this only in very
special cases (eg. audit logs, user session data, etc).</para>
- <para>The @Any annotation describes the column holding the metadata
- information. To link the value of the metadata information and an
- actual entity type, The <classname>@AnyDef</classname> and
- <classname>@AnyDefs</classname> annotations are used.</para>
+ <para>The <classname>@Any</classname> annotation describes the
column
+ holding the metadata information. To link the value of the metadata
+ information and an actual entity type, The
+ <classname>@AnyDef</classname> and
<classname>@AnyDefs</classname>
+ annotations are used.</para>
<programlisting> @Any( metaColumn = @Column( name =
"property_type" ), fetch=FetchType.EAGER )
@AnyMetaDef(
@@ -3638,74 +3742,20 @@
<section id="entity-hibspec-collection-extratype"
revision="1">
<title>Extra collection types</title>
- <section>
- <title>List</title>
-
- <para>Beyond EJB3, Hibernate Annotations supports true
- <classname>List</classname> and
<classname>Array</classname>. Map
- your collection the same way as usual and add the
- @<literal>IndexColumn</literal>. This annotation allows you to
- describe the column that will hold the index. You can also declare
- the index value in DB that represent the first element (aka as base
- index). The usual value is <literal>0</literal> or
- <literal>1</literal>.</para>
-
- <programlisting>@OneToMany(cascade = CascadeType.ALL)
-@IndexColumn(name = "drawer_position", base=1)
-public List<Drawer> getDrawers() {
- return drawers;
-}</programlisting>
-
- <note>
- <para>If you forgot to set <literal>@IndexColumn</literal>,
the
- bag semantic is applied. If you want the bag semantic without the
- limitations of it, consider using
- <literal>(a)CollectionId</literal>.</para>
- </note>
- </section>
-
- <section id="entity-hibspec-collection-extratype-map"
revision="1">
- <title>Map</title>
-
- <para>Hibernate Annotations also supports true Map mappings, if
- <literal>(a)javax.persistence.MapKey</literal> is not set, hibernate
- will map the key element or embeddable object in its/their own
- columns. To override the default columns, you can use
- <literal>(a)org.hibernate.annotations.MapKey</literal> if your key
is
- a basic type (defaulted to <literal>mapkey</literal>) or an
- embeddable object, or you can use
- <literal>(a)org.hibernate.annotations.MapKeyManyToMany</literal> if
- your key is an entity.</para>
-
- <para>Both
<literal>(a)org.hibernate.annotations.MapKey</literal> and
- <literal>(a)org.hibernate.annotations.MapKeyManyToMany</literal>
- allows you to override the target element to be used. This is
- especially useful if your collection does not use generics (or if
- you use interfaces).</para>
-
- <programlisting> @CollectionOfElements(targetElement =
SizeImpl.class)
- @MapKeyManyToMany(<emphasis role="bold">targetEntity =
LuggageImpl.class</emphasis>)
- private Map<Luggage, Size> sizePerLuggage = new HashMap<Luggage,
Size>();</programlisting>
-
- <para></para>
- </section>
-
<section id="entity-hibspec-collection-extratype-indexbidir"
revision="2">
<title>Bidirectional association with indexed collections</title>
<para>A bidirectional association where one end is an indexed
- collection (ie. represented as a <literal>@IndexColumn</literal>,
- <literal>(a)org.hibernate.annotations.MapKey</literal> or
-
<classname>(a)org.hibernate.annotations.MapKeyManyToMany</classname>)
- requires special consideration. If a property on the associated
- class explicitly maps the indexed value, the use of
+ collection (ie. represented as a <literal>@OrderColumn</literal>,
or
+ as a Map) requires special consideration. If a property on the
+ associated class explicitly maps the indexed value, the use of
<methodname>mappedBy</methodname> is permitted:</para>
<programlisting>@Entity
public class Parent {
@OneToMany(mappedBy="parent")
- @org.hibernate.annotations.IndexColumn(name="order")
+ @OrderColumn(name="order")
private List<Child> children;
...
}
@@ -3733,7 +3783,7 @@
<programlisting>@Entity
public class Parent {
@OneToMany
- @org.hibernate.annotations.IndexColumn(name="order")
+ @OrderColumn(name="order")
@JoinColumn(name="parent_id", nullable=false)
private List<Child> children;
...
@@ -3784,148 +3834,6 @@
</section>
<section>
- <title>Collection of element or composite elements</title>
-
- <para>Hibernate Annotations also supports collections of core types
- (Integer, String, Enums, ...), collections of embeddable objects and
- even arrays of primitive types. This is known as collection of
- elements.</para>
-
- <para>A collection of elements has to be annotated as
- <literal>@CollectionOfElements</literal> (as a replacement of
- <literal>@OneToMany</literal>) To define the collection table, the
- <literal>@JoinTable</literal> annotation is used on the
association
- property, <literal>joinColumns</literal> defines the join columns
- between the entity primary table and the collection table
- (inverseJoincolumn is useless and should be left empty). For
- collection of core types or array of primitive types, you can
- override the element column definition using a
- <literal>@Column</literal> on the association property. You can
also
- override the columns of a collection of embeddable object using
- <literal>@AttributeOverride</literal>. To reach the collection
- element, you need to append "element" to the attribute override name
- (eg "element" for core types, or "element.serial" for the
serial
- property of an embeddable element). To reach the index/key of a
- collection, append "key" instead.</para>
-
- <programlisting>@Entity
-public class Boy {
- private Integer id;
- private Set<String> nickNames = new HashSet<String>();
- private int[] favoriteNumbers;
- private Set<Toy> favoriteToys = new HashSet<Toy>();
- private Set<Character> characters = new
HashSet<Character>();
-
- @Id @GeneratedValue
- public Integer getId() {
- return id;
- }
-
- <emphasis role="bold">@CollectionOfElements
- public Set<String></emphasis> getNickNames() {
- return nickNames;
- }
-
- <emphasis role="bold">@CollectionOfElements
- @JoinTable(
- table=@Table(name="BoyFavoriteNumbers"),
- joinColumns = @JoinColumn(name="BoyId")
- )
- @Column(name="favoriteNumber", nullable=false)</emphasis>
- @IndexColumn(name="nbr_index")
- public int[] getFavoriteNumbers() {
- return favoriteNumbers;
- }
-
- <emphasis role="bold">@CollectionOfElements
- @AttributeOverride( name="element.serial",
column=@Column(name="serial_nbr") )</emphasis>
- public Set<Toy> getFavoriteToys() {
- return favoriteToys;
- }
-
- <emphasis role="bold">@CollectionOfElements
- public Set<Character></emphasis> getCharacters() {
- return characters;
- }
- ...
-}
-
-public enum Character {
- GENTLE,
- NORMAL,
- AGGRESSIVE,
- ATTENTIVE,
- VIOLENT,
- CRAFTY
-}
-
-@Embeddable
-public class Toy {
- public String name;
- public String serial;
- public Boy owner;
-
- public String getName() {
- return name;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public String getSerial() {
- return serial;
- }
-
- public void setSerial(String serial) {
- this.serial = serial;
- }
-
- <emphasis role="bold">@Parent</emphasis>
- public Boy getOwner() {
- return owner;
- }
-
- public void setOwner(Boy owner) {
- this.owner = owner;
- }
-
- public boolean equals(Object o) {
- if ( this == o ) return true;
- if ( o == null || getClass() != o.getClass() ) return false;
-
- final Toy toy = (Toy) o;
-
- if ( !name.equals( toy.name ) ) return false;
- if ( !serial.equals( toy.serial ) ) return false;
-
- return true;
- }
-
- public int hashCode() {
- int result;
- result = name.hashCode();
- result = 29 * result + serial.hashCode();
- return result;
- }
-}</programlisting>
-
- <para>On a collection of embeddable objects, the embeddable object
- can have a property annotated with <literal>@Parent</literal>.
This
- property will then point back to the entity containing the
- collection.</para>
-
- <note>
- <para>Previous versions of Hibernate Annotations used the
- <literal>@OneToMany</literal> to mark a collection of elements.
- Due to semantic inconsistencies, we've introduced the annotation
- <literal>@CollectionOfElements</literal>. Marking collections of
- elements the old way still work but is considered deprecated and
- is going to be unsupported in future releases</para>
- </note>
- </section>
-
- <section>
<title>@ManyToAny</title>
<para><classname>@ManyToAny</classname> allows polymorphic
@@ -3996,7 +3904,9 @@
</listitem>
<listitem>
- <para>DELETE_ORPHAN</para>
+ <para>DELETE_ORPHAN (alternatively, use the
+ <methodname>(a)OneToOne.orphanRemoval</methodname> or
+ <methodname>(a)OneToMany.orphanRemoval</methodname>
flag)</para>
</listitem>
<listitem>
@@ -4004,30 +3914,24 @@
</listitem>
<listitem>
- <para>EVICT</para>
+ <para>EVICT (alternatively, use the standard DETACH flag).</para>
</listitem>
</itemizedlist>
<para>This is especially useful for
<literal>SAVE_UPDATE</literal>
(which is the operation cascaded at flush time if you use plain
Hibernate Annotations - Hibernate EntityManager cascade
- <literal>PERSIST</literal> at flush time as per the specification).
- DELETE_ORPHAN applies only to <literal>@OneToMany</literal>
- associations, and indicates that the
- <methodname>delete()/remove()</methodname> operation should be applied
- to any child object that is removed from the association. In other
- words, if a child is dereferenced by a persistent parent and if
- <literal>DELETE_ORPHAN</literal> is used, the "orphaned"
child is
- deleted.</para>
+ <literal>PERSIST</literal> at flush time as per the
+ specification).</para>
- <programlisting>@OneToMany( cascade = {CascadeType.PERSIST,
CascadeType.MERGE} <emphasis
+ <programlisting>@OneToMany( cascade = {CascadeType.PERSIST,
CascadeType.MERGE} <methodname
role="bold">)
-(a)Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE,
- org.hibernate.annotations.CascadeType.DELETE_ORPHAN})</emphasis>
+(a)Cascade(org.hibernate.annotations.CascadeType.REPLICATE)</methodname>
public Collection<Employer> getEmployers()</programlisting>
- <para>It is recommended to use @Cascade to compliment @*To*(cascade=...)
- as shown in the previous example.</para>
+ <para>It is recommended to use <classname>@Cascade</classname>
to
+ compliment <classname>@*To*(cascade=...)</classname> as shown in the
+ previous example.</para>
</section>
<section>
@@ -4142,7 +4046,7 @@
<title>Queries</title>
<para>Since Hibernate has more features on named queries than the one
- defined in the EJB3 specification,
+ defined in the JPA specification,
<literal>(a)org.hibernate.annotations.NamedQuery</literal>,
<literal>(a)org.hibernate.annotations.NamedQueries</literal>,
<literal>(a)org.hibernate.annotations.NamedNativeQuery</literal> and
@@ -4336,8 +4240,6 @@
<emphasis role="bold">@Tuplizer(impl =
DynamicComponentTuplizer.class)</emphasis>
public Country getCountry();
public void setCountry(Country country);
-
-
}</programlisting>
</section>
</section>
Modified: core/trunk/annotations/src/main/java/org/hibernate/annotations/AccessType.java
===================================================================
---
core/trunk/annotations/src/main/java/org/hibernate/annotations/AccessType.java 2010-03-02
12:01:59 UTC (rev 18914)
+++
core/trunk/annotations/src/main/java/org/hibernate/annotations/AccessType.java 2010-03-02
22:39:12 UTC (rev 18915)
@@ -34,6 +34,8 @@
/**
* Property Access type
*
+ * Prefer the standard {@link javax.persistence.Access} annotation
+ *
* @author Emmanuel Bernard
*/
@Target({ TYPE, METHOD, FIELD })
Modified: core/trunk/annotations/src/main/java/org/hibernate/annotations/CascadeType.java
===================================================================
---
core/trunk/annotations/src/main/java/org/hibernate/annotations/CascadeType.java 2010-03-02
12:01:59 UTC (rev 18914)
+++
core/trunk/annotations/src/main/java/org/hibernate/annotations/CascadeType.java 2010-03-02
22:39:12 UTC (rev 18915)
@@ -35,9 +35,11 @@
DELETE,
SAVE_UPDATE,
REPLICATE,
+ /** @deprecated use @OneToOne(orphanRemoval=true) or @OneToMany(orphanRemoval=true) */
+ @Deprecated
DELETE_ORPHAN,
LOCK,
- /** @deprecated use DETACH */
+ /** @deprecated use javax.persistence.CascadeType.DETACH */
@Deprecated
EVICT,
DETACH
Modified:
core/trunk/annotations/src/main/java/org/hibernate/annotations/CollectionOfElements.java
===================================================================
---
core/trunk/annotations/src/main/java/org/hibernate/annotations/CollectionOfElements.java 2010-03-02
12:01:59 UTC (rev 18914)
+++
core/trunk/annotations/src/main/java/org/hibernate/annotations/CollectionOfElements.java 2010-03-02
22:39:12 UTC (rev 18915)
@@ -35,10 +35,12 @@
* Annotation used to mark a collection as a collection of elements or
* a collection of embedded objects
*
+ * @deprecated use @ElementCollection
* @author Emmanuel Bernard
*/
@Target({METHOD, FIELD})
@Retention(RUNTIME)
+@Deprecated
public @interface CollectionOfElements {
/**
* Represent the element class in the collection
Modified: core/trunk/annotations/src/main/java/org/hibernate/annotations/IndexColumn.java
===================================================================
---
core/trunk/annotations/src/main/java/org/hibernate/annotations/IndexColumn.java 2010-03-02
12:01:59 UTC (rev 18914)
+++
core/trunk/annotations/src/main/java/org/hibernate/annotations/IndexColumn.java 2010-03-02
22:39:12 UTC (rev 18915)
@@ -31,6 +31,7 @@
/**
* Describe an index column of a List
+ * Prefer the standard {@link javax.persistence.OrderColumn} annotation
*
* @author Matthew Inger
*/