[hibernate-commits] Hibernate SVN: r18911 - in core/trunk/annotations/src/main: java/org/hibernate/annotations and 1 other directory.

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Mon Mar 1 08:26:57 EST 2010


Author: epbernard
Date: 2010-03-01 08:26:56 -0500 (Mon, 01 Mar 2010)
New Revision: 18911

Modified:
   core/trunk/annotations/src/main/docbook/en/modules/entity.xml
   core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKey.java
   core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKeyManyToMany.java
Log:
HHH-4933 Doc on Map and List support

Modified: core/trunk/annotations/src/main/docbook/en/modules/entity.xml
===================================================================
--- core/trunk/annotations/src/main/docbook/en/modules/entity.xml	2010-03-01 13:23:33 UTC (rev 18910)
+++ core/trunk/annotations/src/main/docbook/en/modules/entity.xml	2010-03-01 13:26:56 UTC (rev 18911)
@@ -24,7 +24,7 @@
 <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
 "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
 <chapter id="entity">
-  <title>Entity Beans</title>
+  <title>Mapping Entities</title>
 
   <section id="entity-overview" revision="2">
     <title>Intro</title>
@@ -957,7 +957,7 @@
           identifier. In the database, it means that the
           <literal>Customer.user</literal> and the
           <literal>CustomerId.userId</literal> properties share the same
-          underlying column (<literal>user_fk</literal> in this case). </para>
+          underlying column (<literal>user_fk</literal> in this case).</para>
 
           <para>In practice, your code only sets the
           <literal>Customer.user</literal> property and the user id value is
@@ -966,7 +966,7 @@
 
           <warning>
             <para>The id value can be copied as late as flush time, don't rely
-            on it until after flush time. </para>
+            on it until after flush time.</para>
           </warning>
 
           <para>While not supported in JPA, Hibernate lets you place your
@@ -1399,7 +1399,7 @@
     </section>
 
     <section id="entity-mapping-association">
-      <title>Mapping entity bean associations/relationships</title>
+      <title>Mapping entity associations/relationships</title>
 
       <section>
         <title>One-to-one</title>
@@ -1493,7 +1493,7 @@
         <literal>passport</literal> and the column id of <literal>Passport
         </literal>is <literal>id</literal>.</para>
 
-        <para>The third possibility (using an association table) is very
+        <para>The third possibility (using an association table) is quite
         exotic.</para>
 
         <programlisting>
@@ -1536,8 +1536,7 @@
         <para>Many-to-one associations are declared at the property level with
         the annotation <literal>@ManyToOne</literal>:</para>
 
-        <programlisting>
- at Entity()
+        <programlisting>@Entity()
 public class Flight implements Serializable {
     <emphasis role="bold">@ManyToOne</emphasis>( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
     @JoinColumn(name="COMP_ID")
@@ -1545,8 +1544,7 @@
         return company;
     }
     ...
-}
-            </programlisting>
+}            </programlisting>
 
         <para>The <literal>@JoinColumn</literal> attribute is optional, the
         default value(s) is like in one to one, the concatenation of the name
@@ -1563,8 +1561,7 @@
         almost all cases. However this is useful when you want to use
         interfaces as the return type instead of the regular entity.</para>
 
-        <programlisting>
- at Entity()
+        <programlisting>@Entity
 public class Flight implements Serializable {
     @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, <emphasis
             role="bold">targetEntity=CompanyImpl.class</emphasis> )
@@ -1577,9 +1574,9 @@
 
 public interface Company {
     ...
-            </programlisting>
+}</programlisting>
 
-        <para>You can alse map a many to one association through an
+        <para>You can also map a many-to-one association through an
         association table. This association table described by the
         <literal>@JoinTable</literal> annotation will contains a foreign key
         referencing back the entity table (through
@@ -1587,8 +1584,7 @@
         referencing the target entity table (through
         <literal>@JoinTable.inverseJoinColumns</literal>).</para>
 
-        <programlisting>
- at Entity()
+        <programlisting>@Entity
 public class Flight implements Serializable {
     @ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
     <emphasis role="bold">@JoinTable(name="Flight_Company",
@@ -1599,8 +1595,7 @@
         return company;
     }
     ...
-}
-            </programlisting>
+}       </programlisting>
       </section>
 
       <section id="entity-mapping-association-collections" revision="1">
@@ -1611,37 +1606,267 @@
           <title>Overview</title>
 
           <para>You can map <classname>Collection</classname>,
-          <literal>List</literal> (ie ordered lists, not indexed lists),
-          <literal>Map</literal> and <classname>Set</classname>. The EJB3
-          specification describes how to map an ordered list (ie a list
-          ordered at load time) using
-          <literal>@javax.persistence.OrderBy</literal> annotation: this
-          annotation takes into parameter a list of comma separated (target
-          entity) properties to order the collection by (eg <code>firstname
-          asc, age desc</code>), if the string is empty, the collection will
-          be ordered by id. For true indexed collections, please refer to the
-          <xref linkend="entity-hibspec" />. EJB3 allows you to map Maps using
-          as a key one of the target entity property using
-          <literal>@MapKey(name="myProperty")</literal> (myProperty 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 (for true map support please refers to <xref
-          linkend="entity-hibspec" />). Many people confuse
-          <literal>&lt;map&gt;</literal> capabilities and
-          <literal>@MapKey</literal> ones. These are two different features.
-          <literal>@MapKey</literal> still has some limitations, please check
-          the forum or the JIRA tracking system for more informations.</para>
+          <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>Hibernate has several notions of collections.</para>
+          <para>Lists can be mapped in two different ways:</para>
 
-          <para></para>
+          <itemizedlist>
+            <listitem>
+              <para>as ordered lists, the order is not materialized in the
+              database</para>
+            </listitem>
 
+            <listitem>
+              <para>as indexed lists, the order is materialized in the
+              database</para>
+            </listitem>
+          </itemizedlist>
+
+          <para>To order lists in memory, add
+          <literal>@javax.persistence.OrderBy</literal> to your property. This
+          annotation takes into parameter a list of comma separated properties
+          (of the target entity) and order 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>
+
+          <programlisting>@Entity
+public class Customer {
+   @Id @GeneratedValue public Integer getId() { return id; }
+   public void setId(Integer id) { this.id = id; }
+   private Integer id;
+
+   @OneToMany(mappedBy="customer")
+   <emphasis role="bold">@OrderBy("number")</emphasis>
+   public List&lt;Order&gt; getOrders() { return orders; }
+   public void setOrders(List&lt;Order&gt; orders) { this.orders = orders; }
+   private List&lt;Order&gt; orders;
+}
+
+ at Entity
+public class Order {
+   @Id @GeneratedValue public Integer getId() { return id; }
+   public void setId(Integer id) { this.id = id; }
+   private Integer id;
+
+   public String getNumber() { return number; }
+   public void setNumber(String number) { this.number = number; }
+   private String number;
+
+   @ManyToOne
+   public Customer getCustomer() { return customer; }
+   public void setCustomer(Customer customer) { this.customer = customer; }
+   private Customer number;
+}
+
+-- Table schema
+|-------------| |----------|
+| Order       | | Customer |
+|-------------| |----------|
+| id          | | id       |
+| number      | |----------| 
+| customer_id |
+|-------------|</programlisting>
+
+          <para>To store the index value in a dedicated column, use the
+          <classname>@javax.persistence.OrderColumn</classname> annotation on
+          your property. This annotations describes the column name and
+          attributes of the column keeping the index value. This column is
+          hosted on the table containing the association foreign key. If the
+          column name is not specified, the default is the name of the
+          referencing property, followed by underscore, followed by
+          <literal>ORDER</literal> (in the following example, it would be
+          <literal>orders_ORDER</literal>).</para>
+
+          <programlisting>@Entity
+public class Customer {
+   @Id @GeneratedValue public Integer getId() { return id; }
+   public void setId(Integer id) { this.id = id; }
+   private Integer id;
+
+   @OneToMany(mappedBy="customer")
+   <emphasis role="bold">@OrderColumn(name"orders_index")</emphasis>
+   public List&lt;Order&gt; getOrders() { return orders; }
+   public void setOrders(List&lt;Order&gt; orders) { this.orders = orders; }
+   private List&lt;Order&gt; orders;
+}
+
+ at Entity
+public class Order {
+   @Id @GeneratedValue public Integer getId() { return id; }
+   public void setId(Integer id) { this.id = id; }
+   private Integer id;
+
+   public String getNumber() { return number; }
+   public void setNumber(String number) { this.number = number; }
+   private String number;
+
+   @ManyToOne
+   public Customer getCustomer() { return customer; }
+   public void setCustomer(Customer customer) { this.customer = customer; }
+   private Customer number;
+}
+
+-- Table schema
+|--------------| |----------|
+| Order        | | Customer |
+|--------------| |----------|
+| id           | | id       |
+| number       | |----------| 
+| customer_id  |
+| orders_index |
+|--------------|</programlisting>
+
+          <note>
+            <para>We recommend you to convert
+            <classname>@org.hibernate.annotations.IndexColumn</classname>
+            usages to <classname>@OrderColumn</classname> unless you are
+            making use of the base property. The <literal>base</literal>
+            property lets you define the index value of the first element (aka
+            as base index). The usual value is <literal>0</literal> or
+            <literal>1</literal>. The default is 0 like in Java.</para>
+          </note>
+
+          <para>Likewise, 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>
+
+          <programlisting>@Entity
+public class Customer {
+   @Id @GeneratedValue public Integer getId() { return id; }
+   public void setId(Integer id) { this.id = id; }
+   private Integer id;
+
+   @OneToMany(mappedBy="customer")
+   <emphasis role="bold">@MapKey(name"number")</emphasis>
+   public Map&lt;String,Order&gt; getOrders() { return orders; }
+   public void setOrders(Map&lt;String,Order&gt; order) { this.orders = orders; }
+   private Map&lt;String,Order&gt; orders;
+}
+
+ at Entity
+public class Order {
+   @Id @GeneratedValue public Integer getId() { return id; }
+   public void setId(Integer id) { this.id = id; }
+   private Integer id;
+
+   public String getNumber() { return number; }
+   public void setNumber(String number) { this.number = number; }
+   private String number;
+
+   @ManyToOne
+   public Customer getCustomer() { return customer; }
+   public void setCustomer(Customer customer) { this.customer = customer; }
+   private Customer number;
+}
+
+-- Table schema
+|-------------| |----------|
+| Order       | | Customer |
+|-------------| |----------|
+| id          | | id       |
+| number      | |----------| 
+| customer_id |
+|-------------|</programlisting>
+
+          <para>Otherwise, the map key is mapped to a dedicated column or
+          columns. To customize things, 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 property followed by underscore followed by
+              <literal>KEY</literal> is used (for example
+              <literal>orders_KEY</literal>).</para>
+            </listitem>
+
+            <listitem>
+              <para><classname>@MapKeyEnumerated</classname> /
+              <classname>@MapKeyTemporal</classname> if the map key type is
+              respectively an enum or a <classname>Date</classname>.</para>
+            </listitem>
+
+            <listitem>
+              <para><classname>@MapKeyJoinColumn</classname>/<classname>@MapKeyJoinColumns</classname>
+              if the map key type is another entity.</para>
+            </listitem>
+
+            <listitem>
+              <para><classname>@AttributeOverride</classname>/<classname>@AttributeOverrides</classname>
+              when the map key is a embeddable object. Use
+              <literal>key.</literal> as a prefix for your embeddable object
+              property names.</para>
+            </listitem>
+          </itemizedlist>
+
+          <para>You can also use <classname>@MapKeyClass</classname> to define
+          the type of the key if you don't use generics (at this stage, you
+          should wonder why at this day and age you don't use
+          generics).</para>
+
+          <programlisting>@Entity
+public class Customer {
+   @Id @GeneratedValue public Integer getId() { return id; }
+   public void setId(Integer id) { this.id = id; }
+   private Integer id;
+
+   @OneToMany @JoinTable(name="Cust_Order")
+   <emphasis role="bold">@MapKeyColumn(name"orders_number")</emphasis>
+   public Map&lt;String,Order&gt; getOrders() { return orders; }
+   public void setOrders(Map&lt;String,Order&gt; orders) { this.orders = orders; }
+   private Map&lt;String,Order&gt; orders;
+}
+
+ at Entity
+public class Order {
+   @Id @GeneratedValue public Integer getId() { return id; }
+   public void setId(Integer id) { this.id = id; }
+   private Integer id;
+
+   public String getNumber() { return number; }
+   public void setNumber(String number) { this.number = number; }
+   private String number;
+
+   @ManyToOne
+   public Customer getCustomer() { return customer; }
+   public void setCustomer(Customer customer) { this.customer = customer; }
+   private Customer number;
+}
+
+-- Table schema
+|-------------| |----------| |---------------|
+| Order       | | Customer | | Cust_Order    |
+|-------------| |----------| |---------------|
+| id          | | id       | | customer_id   |
+| number      | |----------| | order_id      |
+| customer_id |              | orders_number |
+|-------------|              |---------------|</programlisting>
+
+          <para>Let's now explore the various collection semantics based on
+          the mapping you are choosing.</para>
+
           <table>
             <title>Collections semantics</title>
 
@@ -1668,18 +1893,18 @@
 
                   <entry>java.util.List, java.util.Collection</entry>
 
-                  <entry>@org.hibernate.annotations.CollectionOfElements or
-                  @OneToMany or @ManyToMany</entry>
+                  <entry>@ElementCollection or @OneToMany or
+                  @ManyToMany</entry>
                 </row>
 
                 <row>
-                  <entry>Bag semantic with primary key (withtout the
+                  <entry>Bag semantic with primary key (without the
                   limitations of Bag semantic)</entry>
 
                   <entry>java.util.List, java.util.Collection</entry>
 
-                  <entry>(@org.hibernate.annotations.CollectionOfElements or
-                  @OneToMany or @ManyToMany) and @CollectionId</entry>
+                  <entry>(@ElementCollection or @OneToMany or @ManyToMany) and
+                  @CollectionId</entry>
                 </row>
 
                 <row>
@@ -1687,9 +1912,9 @@
 
                   <entry>java.util.List</entry>
 
-                  <entry>(@org.hibernate.annotations.CollectionOfElements or
-                  @OneToMany or @ManyToMany) and
-                  @org.hibernate.annotations.IndexColumn</entry>
+                  <entry>(@ElementCollection or @OneToMany or @ManyToMany) and
+                  (@OrderColumn or
+                  @org.hibernate.annotations.IndexColumn)</entry>
                 </row>
 
                 <row>
@@ -1697,8 +1922,8 @@
 
                   <entry>java.util.Set</entry>
 
-                  <entry>@org.hibernate.annotations.CollectionOfElements or
-                  @OneToMany or @ManyToMany</entry>
+                  <entry>@ElementCollection or @OneToMany or
+                  @ManyToMany</entry>
                 </row>
 
                 <row>
@@ -1706,75 +1931,20 @@
 
                   <entry>java.util.Map</entry>
 
-                  <entry>(@org.hibernate.annotations.CollectionOfElements or
-                  @OneToMany or @ManyToMany) and (nothing or
-                  @org.hibernate.annotations.MapKey/MapKeyManyToMany for true
-                  map support, OR @javax.persistence.MapKey</entry>
+                  <entry>(@ElementCollection or @OneToMany or @ManyToMany) and
+                  ((nothing or @MapKeyJoinColumn/@MapKeyColumn for true map
+                  support) OR @javax.persistence.MapKey)</entry>
                 </row>
               </tbody>
             </tgroup>
           </table>
 
-          <remark>So specifically, java.util.List collections without
-          @org.hibernate.annotations.IndexColumn are going to be considered as
+          <remark>Specifically, java.util.List collections without
+          @OrderColumn or @IndexColumn are going to be considered as
           bags.</remark>
 
-          <para>Collection of primitive, core type or embedded objects is not
-          supported by the EJB3 specification. Hibernate Annotations allows
-          them however (see <xref linkend="entity-hibspec" />).</para>
-
-          <programlisting>@Entity public class City {
-    @OneToMany(mappedBy="city")
-    <emphasis role="bold">@OrderBy("streetName")</emphasis>
-    public List&lt;Street&gt; getStreets() {
-        return streets;
-    }
-...
-}
-
- at Entity public class Street {
-    <emphasis role="bold">public String getStreetName()</emphasis> {
-        return streetName;
-    }
-
-    @ManyToOne
-    public City getCity() {
-        return city;
-    }
-    ...
-}
-
-
- at Entity
-public class Software {
-    @OneToMany(mappedBy="software")
-    <emphasis role="bold">@MapKey(name="codeName")</emphasis>
-    public Map&lt;String, Version&gt; getVersions() {
-        return versions;
-    }
-...
-}
-
- at Entity
- at Table(name="tbl_version")
-public class Version {
-    <emphasis role="bold">public String getCodeName()</emphasis> {...}
-
-    @ManyToOne
-    public Software getSoftware() { ... }
-...
-}</programlisting>
-
-          <para>So <literal>City</literal> has a collection of
-          <literal>Street</literal>s that are ordered by
-          <literal>streetName</literal> (of <literal>Street</literal>) when
-          the collection is loaded. <literal>Software</literal> has a map of
-          <literal>Version</literal>s which key is the
-          <literal>Version</literal> <literal>codeName</literal>.</para>
-
-          <para>Unless the collection is a generic, you will have to define
-          <literal>targetEntity</literal>. This is a annotation attribute that
-          take the target entity class as a value.</para>
+          <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"
@@ -4171,4 +4341,4 @@
 }</programlisting>
     </section>
   </section>
-</chapter>
\ No newline at end of file
+</chapter>

Modified: core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKey.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKey.java	2010-03-01 13:23:33 UTC (rev 18910)
+++ core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKey.java	2010-03-01 13:26:56 UTC (rev 18911)
@@ -32,13 +32,17 @@
 
 /**
  * Define the map key columns as an explicit column holding the map key
- * This is completly different from {@link javax.persistence.MapKey} which use an existing column
+ * This is completely different from {@link javax.persistence.MapKey} which use an existing column
  * This annotation and {@link javax.persistence.MapKey} are mutually exclusive
  *
+ * @deprecated Use {@link javax.persistence.MapKeyColumn}
+ *             This is the default behavior for Map properties marked as @OneToMany, @ManyToMany
+ *             or @ElementCollection
  * @author Emmanuel Bernard
  */
 @Target({METHOD, FIELD})
 @Retention(RUNTIME)
+ at Deprecated
 public @interface MapKey {
 	Column[] columns() default {};
 	/**

Modified: core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKeyManyToMany.java
===================================================================
--- core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKeyManyToMany.java	2010-03-01 13:23:33 UTC (rev 18910)
+++ core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKeyManyToMany.java	2010-03-01 13:26:56 UTC (rev 18911)
@@ -31,13 +31,17 @@
 
 /**
  * Define the map key columns as an explicit column holding the map key
- * This is completly different from {@link javax.persistence.MapKey} which use an existing column
+ * This is completely different from {@link javax.persistence.MapKey} which use an existing column
  * This annotation and {@link javax.persistence.MapKey} are mutually exclusive
  *
+ * @deprecated Use {@link javax.persistence.MapKeyJoinColumn} {@link javax.persistence.MapKeyJoinColumns}
+ *             This is the default behavior for Map properties marked as @OneToMany, @ManyToMany
+ *             or @ElementCollection
  * @author Emmanuel Bernard
  */
 @Target({ElementType.METHOD, ElementType.FIELD})
 @Retention(RetentionPolicy.RUNTIME)
+ at Deprecated
 public @interface MapKeyManyToMany {
 	JoinColumn[] joinColumns() default {};
 	/**



More information about the hibernate-commits mailing list