HHH-5149 Reviewing the collection mapping chapter
git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@19859 1b8cb986-b30d-0410-93ca-fae66ebed9b2
This commit is contained in:
parent
41b09cb0f9
commit
db16c3f29a
|
@ -113,7 +113,7 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set
|
|||
this:</para>
|
||||
|
||||
<example id="example.collection.mapping.annotations">
|
||||
<title>Collection mapping using annotations</title>
|
||||
<title>Collection mapping using @OneToMany and @JoinColumn</title>
|
||||
|
||||
<programlisting role="JAVA">@Entity
|
||||
public class Product {
|
||||
|
@ -126,6 +126,7 @@ public class Product {
|
|||
void setSerialNumber(String sn) { serialNumber = sn; }
|
||||
|
||||
@OneToMany
|
||||
@JoinColumn(name="PART_ID")
|
||||
public Set<Part> getParts() { return parts; }
|
||||
void setParts(Set parts) { this.parts = parts; }
|
||||
}
|
||||
|
@ -137,9 +138,56 @@ public class Part {
|
|||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>Lets have a look how collections are mapped using Hibernate mapping
|
||||
files. Here the first step is to chose the right mapping element, because
|
||||
it depends on the type of interface. For example, a
|
||||
<para>Product describes a unidirectional relationship with Part using the
|
||||
join column PART_ID. In this unidirectional one to many scenario you can
|
||||
also use a join table as seen in <xref
|
||||
linkend="example-one-to-many-with-join-table" />.</para>
|
||||
|
||||
<example id="example-one-to-many-with-join-table">
|
||||
<title id="example-one-to-many-with-join-table">Collection mapping using
|
||||
@OneToMany and @JoinTable</title>
|
||||
|
||||
<programlisting role="JAVA">@Entity
|
||||
public class Product {
|
||||
|
||||
private String serialNumber;
|
||||
private Set<Part> parts = new HashSet<Part>();
|
||||
|
||||
@Id
|
||||
public String getSerialNumber() { return serialNumber; }
|
||||
void setSerialNumber(String sn) { serialNumber = sn; }
|
||||
|
||||
@OneToMany
|
||||
@JoinTable(
|
||||
name="PRODUCT_PARTS",
|
||||
joinColumns = @JoinColumn( name="PRODUCT_ID"),
|
||||
inverseJoinColumns = @JoinColumn( name="PART_ID")
|
||||
)
|
||||
public Set<Part> getParts() { return parts; }
|
||||
void setParts(Set parts) { this.parts = parts; }
|
||||
}
|
||||
|
||||
|
||||
@Entity
|
||||
public class Part {
|
||||
...
|
||||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>Without describing any physical mapping (no
|
||||
<classname>@JoinColumn</classname> or <classname>@JoinTable</classname>),
|
||||
a unidirectional one to many with join table is used. The table name is
|
||||
the concatenation of the owner table name, _, and the other side table
|
||||
name. The foreign key name(s) referencing the owner table is the
|
||||
concatenation of the owner table, _, 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, _, 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>
|
||||
|
||||
<para>Lets have a look now how collections are mapped using Hibernate
|
||||
mapping files. In this case the first step is to chose the right mapping
|
||||
element. It depends on the type of interface. For example, a
|
||||
<literal><set></literal> element is used for mapping properties of
|
||||
type <literal>Set</literal>.</para>
|
||||
|
||||
|
@ -438,6 +486,10 @@ public class Part {
|
|||
<section id="collections-indexed">
|
||||
<title id="section.indexed.collections">Indexed collections</title>
|
||||
|
||||
<para>In the following paragraphs we have a closer at the indexed
|
||||
collections <classname>List</classname> and <classname>Map</classname>
|
||||
how the their index can be mapped in Hibernate.</para>
|
||||
|
||||
<section>
|
||||
<title>Lists</title>
|
||||
|
||||
|
@ -458,7 +510,7 @@ public class Part {
|
|||
<para>To order lists in memory, add
|
||||
<literal>@javax.persistence.OrderBy</literal> to your property. This
|
||||
annotation takes as parameter a list of comma separated properties (of
|
||||
the target entity) and order the collection accordingly (eg
|
||||
the target entity) and orders the collection accordingly (eg
|
||||
<code>firstname asc, age desc</code>), if the string is empty, the
|
||||
collection will be ordered by the primary key of the target
|
||||
entity.</para>
|
||||
|
@ -516,7 +568,7 @@ public class Order {
|
|||
<literal>orders_ORDER</literal>).</para>
|
||||
|
||||
<example>
|
||||
<title>Additional index column using
|
||||
<title>Explicit index column using
|
||||
<classname>@OrderColumn</classname></title>
|
||||
|
||||
<programlisting language="JAVA" role="JAVA">@Entity
|
||||
|
@ -569,11 +621,11 @@ public class Order {
|
|||
is 0 like in Java.</para>
|
||||
</note>
|
||||
|
||||
<para>Using mapping files the index of an array or list is always of
|
||||
type <literal>integer</literal> and is mapped using the
|
||||
<literal><list-index></literal> element. The mapped column
|
||||
contains sequential integers that are numbered from zero by
|
||||
default.</para>
|
||||
<para>Looking again at the Hibernate mapping file equivalent, the
|
||||
index of an array or list is always of type <literal>integer</literal>
|
||||
and is mapped using the <literal><list-index></literal> element.
|
||||
The mapped column contains sequential integers that are numbered from
|
||||
zero by default.</para>
|
||||
|
||||
<example>
|
||||
<title>index-list element for indexed collections in xml
|
||||
|
@ -615,20 +667,21 @@ public class Order {
|
|||
<section>
|
||||
<title>Maps</title>
|
||||
|
||||
<para>Maps can borrow their keys from one of the associated entity
|
||||
properties or have dedicated columns to store an explicit key.</para>
|
||||
<para>The question with <classname>Map</classname>s is where the key
|
||||
value is stored. There are everal options. Maps can borrow their keys
|
||||
from one of the associated entity properties or have dedicated columns
|
||||
to store an explicit key.</para>
|
||||
|
||||
<para>To use one of the target entity property as a key of the map,
|
||||
use <literal>@MapKey(name="myProperty")</literal>
|
||||
(<literal>myProperty</literal> is a property name in the target
|
||||
entity). When using <literal>@MapKey</literal> (without property
|
||||
name), the target entity primary key is used. The map key uses the
|
||||
same column as the property pointed out: there is no additional column
|
||||
defined to hold the map key, and it does make sense since the map key
|
||||
actually represent a target property. Be aware that once loaded, the
|
||||
key is no longer kept in sync with the property, in other words, if
|
||||
you change the property value, the key will not change automatically
|
||||
in your Java model.</para>
|
||||
use <literal>@MapKey(name="myProperty")</literal>, where
|
||||
<literal>myProperty</literal> is a property name in the target entity.
|
||||
When using <literal>@MapKey</literal> without the name attribuate, the
|
||||
target entity primary key is used. The map key uses the same column as
|
||||
the property pointed out. There is no additional column defined to
|
||||
hold the map key, because the map key represent a target property. Be
|
||||
aware that once loaded, the key is no longer kept in sync with the
|
||||
property. In other words, if you change the property value, the key
|
||||
will not change automatically in your Java model.</para>
|
||||
|
||||
<example>
|
||||
<title>Use of target entity property as map key via
|
||||
|
@ -673,14 +726,14 @@ public class Order {
|
|||
|-------------|</programlisting>
|
||||
</example>
|
||||
|
||||
<para>Otherwise, the map key is mapped to a dedicated column or
|
||||
<para>Alternatively the map key is mapped to a dedicated column or
|
||||
columns. In order to customize the mapping use one of the following
|
||||
annotations:</para>
|
||||
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>@<classname>MapKeyColumn</classname> if the map key is a
|
||||
basic type, if you don't specify the column name, the name of the
|
||||
basic type. If you don't specify the column name, the name of the
|
||||
property followed by underscore followed by <literal>KEY</literal>
|
||||
is used (for example <literal>orders_KEY</literal>).</para>
|
||||
</listitem>
|
||||
|
@ -757,11 +810,11 @@ public class Order {
|
|||
the new standard approach described above</para>
|
||||
</note>
|
||||
|
||||
<para>Using Hibernate mapping files there exists similar concepts
|
||||
using <literal><map-key></literal>,
|
||||
<para>Using Hibernate mapping files there exists equivalent concepts
|
||||
to the descibed annotations. You have to use
|
||||
<literal><map-key></literal>,
|
||||
<literal><map-key-many-to-many></literal> and
|
||||
<literal><composite-map-key></literal> which are even a little
|
||||
more flexible since SQL expressions can be used to define the map key.
|
||||
<literal><composite-map-key></literal>.
|
||||
<literal><map-key></literal> is used for any basic type,
|
||||
<literal><map-key-many-to-many></literal> for an entity
|
||||
reference and <literal><composite-map-key></literal> for a
|
||||
|
@ -845,11 +898,11 @@ public class Order {
|
|||
</section>
|
||||
|
||||
<section id="collections-ofvalues" revision="2">
|
||||
<title>Collections of values</title>
|
||||
<title>Collections of basic types and embeddable objects</title>
|
||||
|
||||
<para>In some situations you 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>
|
||||
<classname>@ElementCollection</classname> for this case.</para>
|
||||
|
||||
<example>
|
||||
<title>Collection of basic types mapped via
|
||||
|
@ -869,7 +922,7 @@ public class User {
|
|||
|
||||
<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
|
||||
collection table name defaults 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>
|
||||
|
@ -992,9 +1045,9 @@ public class User {
|
|||
<para>Hibernate supports collections implementing
|
||||
<literal>java.util.SortedMap</literal> and
|
||||
<literal>java.util.SortedSet</literal>. With annotations you declare a
|
||||
sort comparator using <literal>@Sort</literal>. You between the
|
||||
sort comparator using <literal>@Sort</literal>. You chose between the
|
||||
comparator types unsorted, natural or custom. If you want to use your
|
||||
own comparator implementation, you'll also have to express the
|
||||
own comparator implementation, you'll also have to specify the
|
||||
implementation class using the <literal>comparator</literal> attribute.
|
||||
Note that you need to use either a <classname>SortedSet</classname> or a
|
||||
<classname>SortedMap</classname> interface.</para>
|
||||
|
@ -1005,8 +1058,6 @@ public class User {
|
|||
<programlisting language="JAVA" role="JAVA">@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
|
||||
@JoinColumn(name="CUST_ID")
|
||||
@Sort(type = SortType.COMPARATOR, comparator = TicketComparator.class)
|
||||
@Where(clause="1=1")
|
||||
@OnDelete(action=OnDeleteAction.CASCADE)
|
||||
public SortedSet<Ticket> getTickets() {
|
||||
return tickets;
|
||||
}</programlisting>
|
||||
|
@ -1036,17 +1087,18 @@ public SortedSet<Ticket> getTickets() {
|
|||
<literal>unsorted</literal>, <literal>natural</literal> and the name of
|
||||
a class implementing <literal>java.util.Comparator</literal>.</para>
|
||||
|
||||
<para>Sorted collections actually behave like
|
||||
<literal>java.util.TreeSet</literal> or
|
||||
<literal>java.util.TreeMap</literal>.</para>
|
||||
<tip>
|
||||
<para>Sorted collections actually behave like
|
||||
<literal>java.util.TreeSet</literal> or
|
||||
<literal>java.util.TreeMap</literal>.</para>
|
||||
</tip>
|
||||
|
||||
<para>If you want the database itself to order the collection elements,
|
||||
use the <literal>order-by</literal> attribute of <literal>set</literal>,
|
||||
<literal>bag</literal> or <literal>map</literal> mappings. This solution
|
||||
is only available under JDK 1.4 or higher and is implemented using
|
||||
<literal>LinkedHashSet</literal> or <literal>LinkedHashMap</literal>.
|
||||
This performs the ordering in the SQL query and not in the
|
||||
memory.</para>
|
||||
is implemented using <literal>LinkedHashSet</literal> or
|
||||
<literal>LinkedHashMap</literal> and performs the ordering in the SQL
|
||||
query and not in the memory.</para>
|
||||
|
||||
<example>
|
||||
<title>Sorting in database using order-by</title>
|
||||
|
@ -1161,10 +1213,11 @@ public class Soldier {
|
|||
}</programlisting>
|
||||
</example>
|
||||
|
||||
<para>Again a look at the maping file approach. There you can define a
|
||||
bidirectional one-to-many association by mapping a one-to-many
|
||||
association to the same table column(s) as a many-to-one association and
|
||||
declaring the many-valued end <literal>inverse="true"</literal>.</para>
|
||||
<para>How does the mappping of a bidirectional mapping look like in
|
||||
Hibernate mapping xml? There you define a bidirectional one-to-many
|
||||
association by mapping a one-to-many association to the same table
|
||||
column(s) as a many-to-one association and declaring the many-valued end
|
||||
<literal>inverse="true"</literal>.</para>
|
||||
|
||||
<example>
|
||||
<title>Bidirectional one to many via Hibernate mapping files</title>
|
||||
|
@ -1233,9 +1286,7 @@ public class Employee implements Serializable {
|
|||
} </programlisting>
|
||||
</example>
|
||||
|
||||
<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
|
||||
<para>In this example <classname>@JoinTable</classname> defines a
|
||||
<literal>name</literal>, an array of join columns, 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
|
||||
|
@ -1323,11 +1374,12 @@ public class Customer {
|
|||
<para>You cannot select an indexed collection.</para>
|
||||
</note></para>
|
||||
|
||||
<para>Here is an example of a bidirectional many-to-many association
|
||||
that illustrates how each category can have many items and each item can
|
||||
be in many categories:</para>
|
||||
<para><xref linkend="example-many-to-many-mapping-file" /> shows a
|
||||
bidirectional many-to-many association that illustrates how each
|
||||
category can have many items and each item can be in many
|
||||
categories:</para>
|
||||
|
||||
<example>
|
||||
<example id="example-many-to-many-mapping-file">
|
||||
<title>Many to many association using Hibernate mapping files</title>
|
||||
|
||||
<programlisting role="XML"><class name="Category">
|
||||
|
@ -1376,15 +1428,11 @@ session.persist(category); // The relationship will be saved</prog
|
|||
<section id="collections-indexedbidirectional">
|
||||
<title>Bidirectional associations with indexed collections</title>
|
||||
|
||||
<para>Here are some additional consideration for bidirectional mappings
|
||||
with indexed collections using Hibernate mapping files. Refer also to
|
||||
<xref linkend="section.indexed.collections" /> and <xref
|
||||
linkend="section.sorted.collections" />.</para>
|
||||
|
||||
<para>A bidirectional association where one end is represented as a
|
||||
<literal><list></literal> or <literal><map></literal>,
|
||||
requires special consideration. If there is a property of the child
|
||||
class that maps to the index column you can use
|
||||
<para>There are some additional considerations for bidirectional
|
||||
mappings with indexed collections (where one end is represented as a
|
||||
<literal><list></literal> or <literal><map></literal>) when
|
||||
using Hibernate mapping files. If there is a property of the child class
|
||||
that maps to the index column you can use
|
||||
<literal>inverse="true"</literal> on the collection mapping:</para>
|
||||
|
||||
<example>
|
||||
|
@ -1491,12 +1539,12 @@ public class Company {
|
|||
|
||||
<para>The majority of the many-to-many associations and collections of
|
||||
values shown previously all map to tables with composite keys, even
|
||||
though it has been have suggested that entities should have synthetic
|
||||
though it has been suggested that entities should have synthetic
|
||||
identifiers (surrogate keys). A pure association table does not seem to
|
||||
benefit much from a surrogate key, although a collection of composite
|
||||
values <emphasis>might</emphasis>. It is for this reason Hibernate
|
||||
provides a feature that allows you to map many-to-many associations and
|
||||
collections of values to a table with a surrogate key.</para>
|
||||
values <emphasis>might</emphasis>. For this reason Hibernate provides a
|
||||
feature that allows you to map many-to-many associations and collections
|
||||
of values to a table with a surrogate key.</para>
|
||||
|
||||
<para>The <literal><idbag></literal> element lets you map a
|
||||
<literal>List</literal> (or <literal>Collection</literal>) with bag
|
||||
|
|
Loading…
Reference in New Issue