From hibernate-commits at lists.jboss.org Mon Mar 1 08:26:57 2010
Content-Type: multipart/mixed; boundary="===============0683741323612846987=="
MIME-Version: 1.0
From: hibernate-commits at lists.jboss.org
To: hibernate-commits at lists.jboss.org
Subject: [hibernate-commits] Hibernate SVN: r18911 - in
core/trunk/annotations/src/main: java/org/hibernate/annotations and 1 other
directory.
Date: Mon, 01 Mar 2010 08:26:57 -0500
Message-ID: <201003011326.o21DQv5w023073@svn01.web.mwc.hst.phx2.redhat.com>
--===============0683741323612846987==
Content-Type: text/plain; charset="utf-8"
MIME-Version: 1.0
Content-Transfer-Encoding: quoted-printable
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.ja=
va
core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKeyMan=
yToMany.java
Log:
HHH-4933 Doc on Map and List support
Modified: core/trunk/annotations/src/main/docbook/en/modules/entity.xml
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- core/trunk/annotations/src/main/docbook/en/modules/entity.xml 2010-03-0=
1 13:23:33 UTC (rev 18910)
+++ core/trunk/annotations/src/main/docbook/en/modules/entity.xml 2010-03-0=
1 13:26:56 UTC (rev 18911)
@@ -24,7 +24,7 @@
- Entity Beans
+ Mapping Entities
=
Intro
@@ -957,7 +957,7 @@
identifier. In the database, it means that the
Customer.user and the
CustomerId.userId properties share the same
- underlying column (user_fk in this case).
+ underlying column (user_fk in this case).
=
In practice, your code only sets the
Customer.user property and the user id value =
is
@@ -966,7 +966,7 @@
=
The id value can be copied as late as flush time, don't =
rely
- on it until after flush time.
+ on it until after flush time.
=
While not supported in JPA, Hibernate lets you place your
@@ -1399,7 +1399,7 @@
=
- Mapping entity bean associations/relationships
+ Mapping entity associations/relationships
=
One-to-one
@@ -1493,7 +1493,7 @@
passport and the column id of Passport
is id.
=
- The third possibility (using an association table) is very
+ The third possibility (using an association table) is quite
exotic.
=
@@ -1536,8 +1536,7 @@
Many-to-one associations are declared at the property level =
with
the annotation @ManyToOne:
=
-
-(a)Entity()
+ @Entity()
public class Flight implements Serializable {
@ManyToOne( cascade =3D {CascadeTyp=
e.PERSIST, CascadeType.MERGE} )
@JoinColumn(name=3D"COMP_ID")
@@ -1545,8 +1544,7 @@
return company;
}
...
-}
-
+}
=
The @JoinColumn attribute is optional, the
default value(s) is like in one to one, the concatenation of the n=
ame
@@ -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.
=
-
-(a)Entity()
+ @Entity
public class Flight implements Serializable {
@ManyToOne( cascade =3D {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=3DCompanyImpl.class )
@@ -1577,9 +1574,9 @@
=
public interface Company {
...
-
+}
=
- You can alse map a many to one association through an
+ You can also map a many-to-one association through an
association table. This association table described by the
@JoinTable annotation will contains a foreign k=
ey
referencing back the entity table (through
@@ -1587,8 +1584,7 @@
referencing the target entity table (through
@JoinTable.inverseJoinColumns).
=
-
-(a)Entity()
+ @Entity
public class Flight implements Serializable {
@ManyToOne( cascade =3D {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinTable(name=3D"Flight_Company",
@@ -1599,8 +1595,7 @@
return company;
}
...
-}
-
+}
=
@@ -1611,37 +1606,267 @@
Overview
=
You can map Collection,
- List (ie ordered lists, not indexed lists),
- Map and Set. The EJB3
- specification describes how to map an ordered list (ie a list
- ordered at load time) using
- @javax.persistence.OrderBy annotation: this
- annotation takes into parameter a list of comma separated (target
- entity) properties to order the collection by (eg firstname
- asc, age desc
), if the string is empty, the collection wi=
ll
- be ordered by id. For true indexed collections, please refer to =
the
- . EJB3 allows you to map Maps=
using
- as a key one of the target entity property using
- @MapKey(name=3D"myProperty") (myProperty is a
- property name in the target entity). When using
- @MapKey (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 h=
old
- 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 ). Many people confuse
- <map> capabilities and
- @MapKey ones. These are two different feature=
s.
- @MapKey still has some limitations, please ch=
eck
- the forum or the JIRA tracking system for more informations.
+ List, Map and
+ Set pointing to associated entities as
+ one-to-many or many-to-many associations using the
+ @OneToMany or
+ @ManyToMany annotation respectively. If t=
he
+ collection is of a basic type or of an embeddable type, use
+ @ElementCollection. We will describe that=
in
+ more detail in the following subsections but let's first focus on
+ some semantic differences between the various collections.
=
- Hibernate has several notions of collections.
+ Lists can be mapped in two different ways:
=
-
+
+
+ as ordered lists, the order is not materialized in the
+ database
+
=
+
+ as indexed lists, the order is materialized in the
+ database
+
+
+
+ To order lists in memory, add
+ @javax.persistence.OrderBy to your property. =
This
+ annotation takes into parameter a list of comma separated proper=
ties
+ (of the target entity) and order the collection accordingly (eg
+ firstname asc, age desc
), if the string is empty, t=
he
+ collection will be ordered by the primary key of the target
+ entity.
+
+ @Entity
+public class Customer {
+ @Id @GeneratedValue public Integer getId() { return id; }
+ public void setId(Integer id) { this.id =3D id; }
+ private Integer id;
+
+ @OneToMany(mappedBy=3D"customer")
+ @OrderBy("number")
+ public List<Order> getOrders() { return orders; }
+ public void setOrders(List<Order> orders) { this.orders =3D order=
s; }
+ private List<Order> orders;
+}
+
+(a)Entity
+public class Order {
+ @Id @GeneratedValue public Integer getId() { return id; }
+ public void setId(Integer id) { this.id =3D id; }
+ private Integer id;
+
+ public String getNumber() { return number; }
+ public void setNumber(String number) { this.number =3D number; }
+ private String number;
+
+ @ManyToOne
+ public Customer getCustomer() { return customer; }
+ public void setCustomer(Customer customer) { this.customer =3D customer=
; }
+ private Customer number;
+}
+
+-- Table schema
+|-------------| |----------|
+| Order | | Customer |
+|-------------| |----------|
+| id | | id |
+| number | |----------| =
+| customer_id |
+|-------------|
+
+ To store the index value in a dedicated column, use the
+ @javax.persistence.OrderColumn 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 t=
he
+ column name is not specified, the default is the name of the
+ referencing property, followed by underscore, followed by
+ ORDER (in the following example, it would be
+ orders_ORDER).
+
+ @Entity
+public class Customer {
+ @Id @GeneratedValue public Integer getId() { return id; }
+ public void setId(Integer id) { this.id =3D id; }
+ private Integer id;
+
+ @OneToMany(mappedBy=3D"customer")
+ @OrderColumn(name"orders_index")
+ public List<Order> getOrders() { return orders; }
+ public void setOrders(List<Order> orders) { this.orders =3D order=
s; }
+ private List<Order> orders;
+}
+
+(a)Entity
+public class Order {
+ @Id @GeneratedValue public Integer getId() { return id; }
+ public void setId(Integer id) { this.id =3D id; }
+ private Integer id;
+
+ public String getNumber() { return number; }
+ public void setNumber(String number) { this.number =3D number; }
+ private String number;
+
+ @ManyToOne
+ public Customer getCustomer() { return customer; }
+ public void setCustomer(Customer customer) { this.customer =3D customer=
; }
+ private Customer number;
+}
+
+-- Table schema
+|--------------| |----------|
+| Order | | Customer |
+|--------------| |----------|
+| id | | id |
+| number | |----------| =
+| customer_id |
+| orders_index |
+|--------------|
+
+
+ We recommend you to convert
+ @org.hibernate.annotations.IndexColumn
+ usages to @OrderColumn unless you are
+ making use of the base property. The base
+ property lets you define the index value of the first element =
(aka
+ as base index). The usual value is 0 or
+ 1. The default is 0 like in Java.
+
+
+ Likewise, maps can borrow their keys from one of the
+ associated entity properties or have dedicated columns to store =
an
+ explicit key.
+
+ To use one of the target entity property as a key of the m=
ap,
+ use @MapKey(name=3D"myProperty")
+ (myProperty is a property name in the target
+ entity). When using @MapKey (without property
+ name), the target entity primary key is used. The map key uses t=
he
+ 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.
+
+ @Entity
+public class Customer {
+ @Id @GeneratedValue public Integer getId() { return id; }
+ public void setId(Integer id) { this.id =3D id; }
+ private Integer id;
+
+ @OneToMany(mappedBy=3D"customer")
+ @MapKey(name"number")
+ public Map<String,Order> getOrders() { return orders; }
+ public void setOrders(Map<String,Order> order) { this.orders =3D =
orders; }
+ private Map<String,Order> orders;
+}
+
+(a)Entity
+public class Order {
+ @Id @GeneratedValue public Integer getId() { return id; }
+ public void setId(Integer id) { this.id =3D id; }
+ private Integer id;
+
+ public String getNumber() { return number; }
+ public void setNumber(String number) { this.number =3D number; }
+ private String number;
+
+ @ManyToOne
+ public Customer getCustomer() { return customer; }
+ public void setCustomer(Customer customer) { this.customer =3D customer=
; }
+ private Customer number;
+}
+
+-- Table schema
+|-------------| |----------|
+| Order | | Customer |
+|-------------| |----------|
+| id | | id |
+| number | |----------| =
+| customer_id |
+|-------------|
+
+ Otherwise, the map key is mapped to a dedicated column or
+ columns. To customize things, use one of the following
+ annotations:
+
+
+
+ @MapKeyColumn 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
+ KEY is used (for example
+ orders_KEY).
+
+
+
+ @MapKeyEnumerated /
+ @MapKeyTemporal if the map key type is
+ respectively an enum or a Date.
+
+
+
+ @MapKeyJoinColumn/@M=
apKeyJoinColumns
+ if the map key type is another entity.
+
+
+
+ @AttributeOverride/@=
AttributeOverrides
+ when the map key is a embeddable object. Use
+ key. as a prefix for your embeddable obje=
ct
+ property names.
+
+
+
+ You can also use @MapKeyClass to de=
fine
+ 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).
+
+ @Entity
+public class Customer {
+ @Id @GeneratedValue public Integer getId() { return id; }
+ public void setId(Integer id) { this.id =3D id; }
+ private Integer id;
+
+ @OneToMany @JoinTable(name=3D"Cust_Order")
+ @MapKeyColumn(name"orders_number")
+ public Map<String,Order> getOrders() { return orders; }
+ public void setOrders(Map<String,Order> orders) { this.orders =3D=
orders; }
+ private Map<String,Order> orders;
+}
+
+(a)Entity
+public class Order {
+ @Id @GeneratedValue public Integer getId() { return id; }
+ public void setId(Integer id) { this.id =3D id; }
+ private Integer id;
+
+ public String getNumber() { return number; }
+ public void setNumber(String number) { this.number =3D number; }
+ private String number;
+
+ @ManyToOne
+ public Customer getCustomer() { return customer; }
+ public void setCustomer(Customer customer) { this.customer =3D customer=
; }
+ private Customer number;
+}
+
+-- Table schema
+|-------------| |----------| |---------------|
+| Order | | Customer | | Cust_Order |
+|-------------| |----------| |---------------|
+| id | | id | | customer_id |
+| number | |----------| | order_id |
+| customer_id | | orders_number |
+|-------------| |---------------|
+
+ Let's now explore the various collection semantics based on
+ the mapping you are choosing.
+
Collections semantics
=
@@ -1668,18 +1893,18 @@
=
java.util.List, java.util.Collection
=
- @org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany
+ @ElementCollection or @OneToMany or
+ @ManyToMany
=
- Bag semantic with primary key (withtout the
+ Bag semantic with primary key (without the
limitations of Bag semantic)
=
java.util.List, java.util.Collection
=
- (@org.hibernate.annotations.CollectionOfElements =
or
- @OneToMany or @ManyToMany) and @CollectionId
+ (@ElementCollection or @OneToMany or @ManyToMany)=
and
+ @CollectionId
=
@@ -1687,9 +1912,9 @@
=
java.util.List
=
- (@org.hibernate.annotations.CollectionOfElements =
or
- @OneToMany or @ManyToMany) and
- @org.hibernate.annotations.IndexColumn
+ (@ElementCollection or @OneToMany or @ManyToMany)=
and
+ (@OrderColumn or
+ @org.hibernate.annotations.IndexColumn)
=
@@ -1697,8 +1922,8 @@
=
java.util.Set
=
- @org.hibernate.annotations.CollectionOfElements or
- @OneToMany or @ManyToMany
+ @ElementCollection or @OneToMany or
+ @ManyToMany
=
@@ -1706,75 +1931,20 @@
=
java.util.Map
=
- (@org.hibernate.annotations.CollectionOfElements =
or
- @OneToMany or @ManyToMany) and (nothing or
- @org.hibernate.annotations.MapKey/MapKeyManyToMany for t=
rue
- map support, OR @javax.persistence.MapKey
+ (@ElementCollection or @OneToMany or @ManyToMany)=
and
+ ((nothing or @MapKeyJoinColumn/@MapKeyColumn for true map
+ support) OR @javax.persistence.MapKey)
=
- So specifically, java.util.List collections without
- @org.hibernate.annotations.IndexColumn are going to be considere=
d as
+ Specifically, java.util.List collections without
+ @OrderColumn or @IndexColumn are going to be considered as
bags.
=
- Collection of primitive, core type or embedded objects is =
not
- supported by the EJB3 specification. Hibernate Annotations allows
- them however (see ).
-
- @Entity public class City {
- @OneToMany(mappedBy=3D"city")
- @OrderBy("streetName")
- public List<Street> getStreets() {
- return streets;
- }
-...
-}
-
-(a)Entity public class Street {
- public String getStreetName() {
- return streetName;
- }
-
- @ManyToOne
- public City getCity() {
- return city;
- }
- ...
-}
-
-
-(a)Entity
-public class Software {
- @OneToMany(mappedBy=3D"software")
- @MapKey(name=3D"codeName")
- public Map<String, Version> getVersions() {
- return versions;
- }
-...
-}
-
-(a)Entity
-(a)Table(name=3D"tbl_version")
-public class Version {
- public String getCodeName() {...}
-
- @ManyToOne
- public Software getSoftware() { ... }
-...
-}
-
- So City has a collection of
- Streets that are ordered by
- streetName (of Street) when
- the collection is loaded. Software has a map =
of
- Versions which key is the
- Version codeName.
-
- Unless the collection is a generic, you will have to define
- targetEntity. This is a annotation attribute =
that
- take the target entity class as a value.
+ More support for collections are available via Hibernate
+ specific extensions (see ).=
para>
=
-
\ No newline at end of file
+
Modified: core/trunk/annotations/src/main/java/org/hibernate/annotations/Ma=
pKey.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKey.j=
ava 2010-03-01 13:23:33 UTC (rev 18910)
+++ core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKey.j=
ava 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} whic=
h use an existing column
* This annotation and {@link javax.persistence.MapKey} are mutually exclu=
sive
*
+ * @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)
+(a)Deprecated
public @interface MapKey {
Column[] columns() default {};
/**
Modified: core/trunk/annotations/src/main/java/org/hibernate/annotations/Ma=
pKeyManyToMany.java
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=
=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D
--- core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKeyMa=
nyToMany.java 2010-03-01 13:23:33 UTC (rev 18910)
+++ core/trunk/annotations/src/main/java/org/hibernate/annotations/MapKeyMa=
nyToMany.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} whic=
h use an existing column
* This annotation and {@link javax.persistence.MapKey} are mutually exclu=
sive
*
+ * @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)
+(a)Deprecated
public @interface MapKeyManyToMany {
JoinColumn[] joinColumns() default {};
/**
--===============0683741323612846987==--