From 6a7727163eaa04b637929f47c23b90dd1bc1641b Mon Sep 17 00:00:00 2001 From: Emmanuel Bernard Date: Tue, 2 Mar 2010 22:39:12 +0000 Subject: [PATCH] HHH-4933 deprecate legacy annotations, document @ElementCollection, reorganize collection description, remove legacy annotations documentation when a new one is in place git-svn-id: https://svn.jboss.org/repos/hibernate/core/trunk@18915 1b8cb986-b30d-0410-93ca-fae66ebed9b2 --- .../src/main/docbook/en/modules/entity.xml | 1210 ++++++++--------- .../org/hibernate/annotations/AccessType.java | 2 + .../hibernate/annotations/CascadeType.java | 4 +- .../annotations/CollectionOfElements.java | 2 + .../hibernate/annotations/IndexColumn.java | 1 + 5 files changed, 564 insertions(+), 655 deletions(-) diff --git a/annotations/src/main/docbook/en/modules/entity.xml b/annotations/src/main/docbook/en/modules/entity.xml index bc000f40ab..24db0a730c 100644 --- a/annotations/src/main/docbook/en/modules/entity.xml +++ b/annotations/src/main/docbook/en/modules/entity.xml @@ -60,9 +60,8 @@
Marking a POJO as persistent entity - Every persistent POJO class is an entity bean and is declared - using the @Entity annotation (at the class - level): + Every persistent POJO class is an entity and is declared using the + @Entity annotation (at the class level): @Entity public class Flight implements Serializable { @@ -74,11 +73,11 @@ public class Flight implements Serializable { public void setId(Long id) { this.id = id; } } - @Entity declares the class as an entity bean - (i.e. a persistent POJO class), @Id 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. + @Entity declares the class as an entity (i.e. a + persistent POJO class), @Id 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. The concept of configuration by exception is central to the JPA @@ -100,8 +99,8 @@ public class Flight implements Serializable { @Table is set at the class level; it allows you to define the table, catalog, and schema names for your entity - bean mapping. If no @Table is defined the default - values are used: the unqualified class name of the entity. + mapping. If no @Table is defined the default values + are used: the unqualified class name of the entity. @Entity @Table(name="tbl_sky") @@ -140,8 +139,8 @@ public class Sky implements Serializable {
Versioning for optimistic locking - You can add optimistic locking capability to an entity bean - using the @Version annotation: + You can add optimistic locking capability to an entity using the + @Version annotation: @Entity public class Flight implements Serializable { @@ -176,12 +175,12 @@ public class Flight implements Serializable { Declaring basic property mappings 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 @Transient. - Not having an annotation for your property is equivalent to the - appropriate @Basic annotation. The - @Basic annotation allows you to declare the - fetching strategy for a property: + depending on the access type) of an entity is considered persistent, + unless you annotate it as @Transient. Not having an + annotation for your property is equivalent to the appropriate + @Basic annotation. The @Basic + annotation allows you to declare the fetching strategy for a + property: public transient int counter; //transient property @@ -568,7 +567,7 @@ public class Country implements Serializable { entity (note that you can override that using the @Access annotation). - The Person entity bean has two component + The Person entity has two component properties, homeAddress and bornIn. homeAddress property has not been annotated, but Hibernate will guess that it is a persistent @@ -654,9 +653,9 @@ public class Country implements Serializable { Mapping identifier properties The @Id 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 @GeneratedValue annotation.
@@ -1404,7 +1403,7 @@ public class Plane extends FlyingObject {
One-to-one - You can associate entity beans through a one-to-one relationship + You can associate entities through a one-to-one relationship using @OneToOne. 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 @@ public class Passport implements Serializable { The third possibility (using an association table) is quite exotic. - -@Entity + @Entity public class Customer implements Serializable { @OneToOne(cascade = CascadeType.ALL) @JoinTable(name = "CustomerPassports", @@ -1513,8 +1511,7 @@ public class Passport implements Serializable { @OneToOne(mappedBy = "passport") public Customer getOwner() { ... -} - +} A Customer is linked to a Passport through a association table named @@ -1601,20 +1598,392 @@ public class Flight implements Serializable {
Collections + You can map Collection, + 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 the + collection is of a basic type or of an embeddable type, use + @ElementCollection. We will describe that in + more detail in the following subsections. + +
+ One-to-many + + One-to-many associations are declared at the property level + with the annotation @OneToMany. One to many + associations may be bidirectional. + +
+ Bidirectional + + 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 + @OneToMany(mappedBy=...) + + @Entity +public class Troop { + @OneToMany(mappedBy="troop") + public Set<Soldier> getSoldiers() { + ... +} + +@Entity +public class Soldier { + @ManyToOne + @JoinColumn(name="troop_fk") + public Troop getTroop() { + ... +} + + Troop has a bidirectional one to many + relationship with Soldier through the + troop property. You don't have to (must not) + define any physical mapping in the mappedBy + side. + + To map a bidirectional one to many, with the one-to-many + side as the owning side, you have to remove the + mappedBy element and set the many to one + @JoinColumn as insertable and updatable to + false. This solution is not optimized and will produce some + additional UPDATE statements. + + @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() { + ... +} +
+ +
+ Unidirectional + + 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 + @JoinColumn + + @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 +} + + Customer describes a unidirectional + relationship with Ticket using the join column + CUST_ID. +
+ +
+ Unidirectional with join table + + A unidirectional one to many with join table is much + preferred. This association is described through an + @JoinTable. + + @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 +} + + Trainer describes a unidirectional + relationship with Monkey using the join + table TrainedMonkeys, with a foreign key + trainer_id to Trainer + (joinColumns) and a foreign key + monkey_id to Monkey + (inversejoinColumns). +
+ +
+ Defaults + + 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, _, 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. + + @Entity +public class Trainer { + @OneToMany + public Set<Tiger> getTrainedTigers() { + ... +} + +@Entity +public class Tiger { + ... //no bidir +} + + Trainer describes a unidirectional + relationship with Tiger using the join + table Trainer_Tiger, with a foreign key + trainer_id to Trainer (table + name, _, trainer id) and a foreign key + trainedTigers_id to Monkey + (property name, _, Tiger primary column). +
+
+ +
+ Many-to-many + +
+ Definition + + A many-to-many association is defined logically using the + @ManyToMany annotation. You also have to + describe the association table and the join conditions using the + @JoinTable 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): + + @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; + } + ... +} + + @Entity +public class Employee implements Serializable { + @ManyToMany( + cascade = {CascadeType.PERSIST, CascadeType.MERGE}, + mappedBy = "employees", + targetEntity = Employer.class + ) + public Collection getEmployers() { + return employers; + } +} + + We've already shown the many declarations and the detailed + attributes for associations. We'll go deeper in the + @JoinTable description, it defines a + name, 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 Employee primary + key (the "other side"). + + As seen previously, the other side don't have to (must not) + describe the physical mapping: a simple + mappedBy argument containing the owner side + property name bind the two. +
+ +
+ Default values + + 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, + _ and the other side table name. The foreign key + name(s) referencing the owner table is the concatenation of the + owner table name, _ and the owner primary key + column(s). 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). These are the same rules + used for a unidirectional one to many relationship. + + +@Entity +public class Store { + @ManyToMany(cascade = CascadeType.PERSIST) + public Set<City> getImplantedIn() { + ... + } +} + +@Entity +public class City { + ... //no bidirectional relationship +} + + + A Store_City is used as the join table. + The Store_id column is a foreign key to the + Store table. The + implantedIn_id column is a foreign key to the + City table. + + 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, _ and the + other side table name. The foreign key name(s) referencing the + owner table is the concatenation of the other side property name, + _, and the owner primary key column(s). 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). These are the same rules + used for a unidirectional one to many relationship. + + @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() { + ... + } +} + + A Store_Customer is used as the join + table. The stores_id column is a foreign key to + the Store table. The + customers_id column is a foreign key to the + Customer table. +
+
+ +
+ Collection of basic types or embeddable objects + + 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 @ElementCollection in this + case. + + @Entity +public class User { + [...] + public String getLastname() { ...} + + @ElementCollection + @CollectionTable(name="Nicknames", joinColumns=@JoinColumn(name="user_id")) + @Column(name="nickname") + public Set<String> getNicknames() { ... } +} + + The collection table holding the collection data is set using + the @CollectionTable 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 + User_nicknames. + + The column holding the basic type is set using the + @Column annotation. If omitted, the column + name defaults to the property name: in our example, it would be + nicknames. + + 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 + @AttributeOverride annotation. + + @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() {...} + [...] +} + + Such an embeddable object cannot contains a collection + itself. + + + in @AttributeOverride, you must use + the value. prefix to override properties of the + embeddable object used in the map value and the + key. prefix to override properties of the + embeddable object used in the map key. + + @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() { ... } + + + + We recommend you to migrate from + @org.hibernate.annotations.CollectionOfElements + to the new @ElementCollection + annotation. + +
+
- Overview - - You can map Collection, - 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 the - 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. + Indexed collections (List, Map) Lists can be mapped in two different ways: @@ -1864,6 +2233,13 @@ public class Order { | customer_id | | orders_number | |-------------| |---------------| + + We recommend you to migrate from + @org.hibernate.annotations.MapKey / + @org.hibernate.annotation.MapKeyManyToMany + to the new standard approach described above. + + Let's now explore the various collection semantics based on the mapping you are choosing. @@ -1946,308 +2322,6 @@ public class Order { More support for collections are available via Hibernate specific extensions (see ).
- -
- One-to-many - - One-to-many associations are declared at the property level - with the annotation @OneToMany. One to many - associations may be bidirectional. - -
- Bidirectional - - 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 @OneToMany( mappedBy=... - ) - - @Entity -public class Troop { - @OneToMany(mappedBy="troop") - public Set<Soldier> getSoldiers() { - ... -} - -@Entity -public class Soldier { - @ManyToOne - @JoinColumn(name="troop_fk") - public Troop getTroop() { - ... -} - - Troop has a bidirectional one to many - relationship with Soldier through the - troop property. You don't have to (must not) - define any physical mapping in the mappedBy - side. - - To map a bidirectional one to many, with the one-to-many - side as the owning side, you have to remove the - mappedBy element and set the many to one - @JoinColumn as insertable and updatable to - false. This solution is obviously not optimized and will produce - some additional UPDATE statements. - - @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() { - ... -} -
- -
- Unidirectional - - 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 - @JoinColumn - - -@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 -} - - - Customer describes a unidirectional - relationship with Ticket using the join column - CUST_ID. -
- -
- Unidirectional with join table - - A unidirectional one to many with join table is much - preferred. This association is described through an - @JoinTable. - - -@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 -} - - - Trainer describes a unidirectional - relationship with Monkey using the join - table TrainedMonkeys, with a foreign key - trainer_id to Trainer - (joinColumns) and a foreign key - monkey_id to Monkey - (inversejoinColumns). -
- -
- Defaults - - 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, _, 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. - - -@Entity -public class Trainer { - @OneToMany - public Set<Tiger> getTrainedTigers() { - ... -} - -@Entity -public class Tiger { - ... //no bidir -} - - - Trainer describes a unidirectional - relationship with Tiger using the join - table Trainer_Tiger, with a foreign key - trainer_id to Trainer (table - name, _, trainer id) and a foreign key - trainedTigers_id to Monkey - (property name, _, Tiger primary column). -
-
- -
- Many-to-many - -
- Definition - - A many-to-many association is defined logically using the - @ManyToMany annotation. You also have to - describe the association table and the join conditions using the - @JoinTable 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): - - -@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; - } - ... -} - - - -@Entity -public class Employee implements Serializable { - @ManyToMany( - cascade = {CascadeType.PERSIST, CascadeType.MERGE}, - mappedBy = "employees", - targetEntity = Employer.class - ) - public Collection getEmployers() { - return employers; - } -} - - - We've already shown the many declarations and the detailed - attributes for associations. We'll go deeper in the - @JoinTable description, it defines a - name, 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 Employee primary - key (the "other side"). - - As seen previously, the other side don't have to (must not) - describe the physical mapping: a simple - mappedBy argument containing the owner side - property name bind the two. -
- -
- Default values - - 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, - _ and the other side table name. The foreign key - name(s) referencing the owner table is the concatenation of the - owner table name, _ and the owner primary key - column(s). 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). These are the same rules - used for a unidirectional one to many relationship. - - -@Entity -public class Store { - @ManyToMany(cascade = CascadeType.PERSIST) - public Set<City> getImplantedIn() { - ... - } -} - -@Entity -public class City { - ... //no bidirectional relationship -} - - - A Store_City is used as the join table. - The Store_id column is a foreign key to the - Store table. The - implantedIn_id column is a foreign key to the - City table. - - 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, _ and the - other side table name. The foreign key name(s) referencing the - owner table is the concatenation of the other side property name, - _, and the owner primary key column(s). 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). These are the same rules - used for a unidirectional one to many relationship. - - -@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() { - ... - } -} - - - A Store_Customer is used as the join - table. The stores_id column is a foreign key to - the Store table. The - customers_id column is a foreign key to the - Customer table. -
-
@@ -2255,35 +2329,40 @@ public class Customer { You probably have noticed the cascade attribute taking an array of CascadeType 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: + 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: - CascadeType.PERSIST: cascades the persist (create) operation - to associated entities persist() is called or if the entity is - managed + CascadeType.PERSIST: cascades the persist + (create) operation to associated entities persist() is called or + if the entity is managed - CascadeType.MERGE: cascades the merge operation to - associated entities if merge() is called or if the entity is - managed + CascadeType.MERGE: cascades the merge + operation to associated entities if merge() is called or if the + entity is managed - CascadeType.REMOVE: cascades the remove operation to - associated entities if delete() is called + CascadeType.REMOVE: cascades the remove + operation to associated entities if delete() is called - CascadeType.REFRESH: cascades the refresh operation to - associated entities if refresh() is called + CascadeType.REFRESH: cascades the refresh + operation to associated entities if refresh() is called - CascadeType.ALL: all of the above + CascadeType.DETACH: cascades the detach + operation to associated entities if detach() is called + + + + CascadeType.ALL: all of the above @@ -2293,8 +2372,30 @@ public class Customer { linkend="entity-hibspec-cascade" /> for more information - Please refer to the chapter 6.3 of the EJB3 specification for + Please refer to the chapter 6.3 of the JPA specification for more information on cascading and create/merge semantics. + + You can also enable the orphan removal semantic. If an entity is + removed from a @OneToMany collection or an + associated entity is dereferenced from a + @OneToOne association, this associated entity + can be marked for deletion if orphanRemoval 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. + + @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
@@ -2313,9 +2414,9 @@ public class Customer { EAGER. For more information about static fetching, check . - The recommanded approach is to use LAZY onn + The recommanded approach is to use LAZY on all static fetching definitions and override this choice dynamically - through JPA-QL. JPA-QL has a fetch keyword that + through JP-QL. JP-QL has a fetch 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. @@ -2323,7 +2424,8 @@ public class Customer {
- Mapping composite primary and foreign keys + Mapping composite primary keys and foreign keys to composite + primary keys Composite primary keys use a embedded class as the primary key representation, so you'd use the @Id and @@ -2331,11 +2433,10 @@ public class Customer { the @EmbeddedId annotation. Note that the dependent class has to be serializable and implements equals()/hashCode(). - You can also use @IdClass as described in . + You can also use @IdClass. These are more detailed in + . - -@Entity + @Entity public class RegionalArticle implements Serializable { @Id @@ -2343,21 +2444,18 @@ public class RegionalArticle implements Serializable { } @Embeddable -public class RegionalArticlePk implements Serializable { ... } - +public class RegionalArticlePk implements Serializable { ... } or alternatively - -@Entity + @Entity public class RegionalArticle implements Serializable { @EmbeddedId public RegionalArticlePk getPk() { ... } } -public class RegionalArticlePk implements Serializable { ... } - +public class RegionalArticlePk implements Serializable { ... } @Embeddable inherit the access type of its owning entity unless @Access is used. Composite @@ -2368,8 +2466,7 @@ public class RegionalArticlePk implements Serializable { ... } explicitly. Otherwise, Hibernate will suppose that you use the same order of columns as in the primary key declaration. - -@Entity + @Entity public class Parent implements Serializable { @Id public ParentPk id; @@ -2383,11 +2480,9 @@ public class Parent implements Serializable { }) public Set<Child> children; //unidirectional ... -} - +} - -@Entity + @Entity public class Child implements Serializable { @Id @GeneratedValue public Integer id; @@ -2399,17 +2494,14 @@ public class Child implements Serializable { @JoinColumn(name="parentFirstName", referencedColumnName = "firstName") }) public Parent parent; //unidirectional -} - +} - -@Embeddable + @Embeddable public class ParentPk implements Serializable { String firstName; String lastName; ... -} - +} Note the explicit usage of the referencedColumnName. @@ -2418,15 +2510,14 @@ public class ParentPk implements Serializable {
Mapping secondary tables - You can map a single entity bean to several tables using the + You can map a single entity to several tables using the @SecondaryTable or @SecondaryTables class level annotations. To express that a column is in a particular table, use the table parameter of @Column or @JoinColumn. - -@Entity + @Entity @Table(name="MainCat") @SecondaryTables({ @SecondaryTable(name="Cat1", pkJoinColumns={ @@ -2459,7 +2550,7 @@ public class Cat implements Serializable { public String getStoryPart2() { return storyPart2; } - +} In this example, name will be in MainCat. storyPart1 will be in @@ -2479,16 +2570,33 @@ public class Cat implements Serializable {
Mapping Queries + While you can write queries in your code, it is considered a good + practice to externalize them: + + + + it make developer/DBA communications easier + + + + named queries are pre-compiled by Hibernate at startup + time + + + + Unfortunately, you lose the type-safety of queries written using the + Criteria API. +
- Mapping JPAQL/HQL queries + Mapping JP-QL/HQL queries - You can map EJBQL/HQL queries using annotations. + You can map JP-QL/HQL queries using annotations. @NamedQuery and @NamedQueries 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. + 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. <entity-mappings> <named-query name="plane.getAll"> @@ -2512,14 +2620,13 @@ public class MyDao { ... } ... -} - +} You can also provide some hints to a query through an array of QueryHint through a hints attribute. - The availabe Hibernate hints are + The available Hibernate hints are @@ -2592,6 +2699,11 @@ public class MyDao { + + You can also define the lock mode by which the returned entities + should be locked using the lockMode property. This is + equivalent to the optional lock mode of the entitymanager lookup + operations.
@@ -2618,10 +2730,10 @@ public class MyDao { @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", resultSetMapping="joinMapping") + + "from Night night, Area area where night.area_id = area.id", + resultSetMapping="joinMapping") @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 @@ public class MyDao { see an implicit declaration of the property / column. @Entity -@SqlResultSetMapping(name="implicit", entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class)) -@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultSetMapping="implicit") +@SqlResultSetMapping(name="implicit", + entities=@EntityResult(entityClass=SpaceShip.class)) +@NamedNativeQuery(name="implicitSample", + query="select * from SpaceShip", + resultSetMapping="implicit") public class SpaceShip { private String name; private String model; @@ -2689,7 +2804,7 @@ public class SpaceShip { @Entity @SqlResultSetMapping(name="compositekey", - entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class, + entities=@EntityResult(entityClass=SpaceShip.class, fields = { @FieldResult(name="name", column = "name"), @FieldResult(name="model", column = "model"), @@ -2786,13 +2901,6 @@ public class Captain implements Serializable { } - - 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 :-) - - If you retrieve a single entity and if you use the default mapping, you can use the resultClass attribute instead of resultSetMapping: @@ -3136,24 +3244,20 @@ public long getObjectVolume() Place your annotations before the package declaration. - -@TypeDef( - name = "phoneNumber", - defaultForType = PhoneNumber.class, - typeClass = PhoneNumberType.class + @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; + [...] +} The following example shows the usage of the parameters attribute to customize the @@ -3178,8 +3282,7 @@ public class Forest { @Type(type="caster") public String getSmallText() { ... -} - +} When using composite user type, you will have to express column definitions. The @Columns has been introduced for @@ -3248,7 +3351,8 @@ person == person.address.owner @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 @@ public class Antenna { Annotate your property as @Generated 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. + 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. @Version properties cannot be @Generated(INSERT) by design, it has to be either @@ -3282,8 +3387,6 @@ public class Antenna { public Owner getOwner() { return owner; } - -
@@ -3394,7 +3497,7 @@ alter table Child add constraint FK_PARENT foreign key (parent_id) references Pa
Lazy options and fetching modes - EJB3 comes with the fetch option to define + JPA comes with the fetch 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: @@ -3503,10 +3606,11 @@ alter table Child add constraint FK_PARENT foreign key (parent_id) references Pa mapping (polymorphic) associations. You should use this only in very special cases (eg. audit logs, user session data, etc). - The @Any annotation describes the column holding the metadata - information. To link the value of the metadata information and an - actual entity type, The @AnyDef and - @AnyDefs annotations are used. + The @Any annotation describes the column + holding the metadata information. To link the value of the metadata + information and an actual entity type, The + @AnyDef and @AnyDefs + annotations are used. @Any( metaColumn = @Column( name = "property_type" ), fetch=FetchType.EAGER ) @AnyMetaDef( @@ -3638,74 +3742,20 @@ alter table Man_Woman add constraint TO_MAN_FK foreign key (man_id) references M
Extra collection types -
- List - - Beyond EJB3, Hibernate Annotations supports true - List and Array. Map - your collection the same way as usual and add the - @IndexColumn. 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 0 or - 1. - - @OneToMany(cascade = CascadeType.ALL) -@IndexColumn(name = "drawer_position", base=1) -public List<Drawer> getDrawers() { - return drawers; -} - - - If you forgot to set @IndexColumn, the - bag semantic is applied. If you want the bag semantic without the - limitations of it, consider using - @CollectionId. - -
- -
- Map - - Hibernate Annotations also supports true Map mappings, if - @javax.persistence.MapKey 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 - @org.hibernate.annotations.MapKey if your key is - a basic type (defaulted to mapkey) or an - embeddable object, or you can use - @org.hibernate.annotations.MapKeyManyToMany if - your key is an entity. - - Both @org.hibernate.annotations.MapKey and - @org.hibernate.annotations.MapKeyManyToMany - 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). - - @CollectionOfElements(targetElement = SizeImpl.class) - @MapKeyManyToMany(targetEntity = LuggageImpl.class) - private Map<Luggage, Size> sizePerLuggage = new HashMap<Luggage, Size>(); - - -
-
Bidirectional association with indexed collections A bidirectional association where one end is an indexed - collection (ie. represented as a @IndexColumn, - @org.hibernate.annotations.MapKey or - @org.hibernate.annotations.MapKeyManyToMany) - requires special consideration. If a property on the associated - class explicitly maps the indexed value, the use of + collection (ie. represented as a @OrderColumn, or + as a Map) requires special consideration. If a property on the + associated class explicitly maps the indexed value, the use of mappedBy is permitted: @Entity public class Parent { @OneToMany(mappedBy="parent") - @org.hibernate.annotations.IndexColumn(name="order") + @OrderColumn(name="order") private List<Child> children; ... } @@ -3733,7 +3783,7 @@ public class Child { @Entity public class Parent { @OneToMany - @org.hibernate.annotations.IndexColumn(name="order") + @OrderColumn(name="order") @JoinColumn(name="parent_id", nullable=false) private List<Child> children; ... @@ -3783,148 +3833,6 @@ public class Passport { }
-
- Collection of element or composite elements - - 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. - - A collection of elements has to be annotated as - @CollectionOfElements (as a replacement of - @OneToMany) To define the collection table, the - @JoinTable annotation is used on the association - property, joinColumns 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 - @Column on the association property. You can also - override the columns of a collection of embeddable object using - @AttributeOverride. 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. - - @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; - } - - @CollectionOfElements - public Set<String> getNickNames() { - return nickNames; - } - - @CollectionOfElements - @JoinTable( - table=@Table(name="BoyFavoriteNumbers"), - joinColumns = @JoinColumn(name="BoyId") - ) - @Column(name="favoriteNumber", nullable=false) - @IndexColumn(name="nbr_index") - public int[] getFavoriteNumbers() { - return favoriteNumbers; - } - - @CollectionOfElements - @AttributeOverride( name="element.serial", column=@Column(name="serial_nbr") ) - public Set<Toy> getFavoriteToys() { - return favoriteToys; - } - - @CollectionOfElements - public Set<Character> 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; - } - - @Parent - 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; - } -} - - On a collection of embeddable objects, the embeddable object - can have a property annotated with @Parent. This - property will then point back to the entity containing the - collection. - - - Previous versions of Hibernate Annotations used the - @OneToMany to mark a collection of elements. - Due to semantic inconsistencies, we've introduced the annotation - @CollectionOfElements. Marking collections of - elements the old way still work but is considered deprecated and - is going to be unsupported in future releases - -
-
@ManyToAny @@ -3996,7 +3904,9 @@ public class Toy { - DELETE_ORPHAN + DELETE_ORPHAN (alternatively, use the + @OneToOne.orphanRemoval or + @OneToMany.orphanRemoval flag) @@ -4004,30 +3914,24 @@ public class Toy { - EVICT + EVICT (alternatively, use the standard DETACH flag). This is especially useful for SAVE_UPDATE (which is the operation cascaded at flush time if you use plain Hibernate Annotations - Hibernate EntityManager cascade - PERSIST at flush time as per the specification). - DELETE_ORPHAN applies only to @OneToMany - associations, and indicates that the - delete()/remove() 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 - DELETE_ORPHAN is used, the "orphaned" child is - deleted. + PERSIST at flush time as per the + specification). - @OneToMany( cascade = {CascadeType.PERSIST, CascadeType.MERGE} @OneToMany( cascade = {CascadeType.PERSIST, CascadeType.MERGE} ) -@Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, - org.hibernate.annotations.CascadeType.DELETE_ORPHAN}) +@Cascade(org.hibernate.annotations.CascadeType.REPLICATE) public Collection<Employer> getEmployers() - It is recommended to use @Cascade to compliment @*To*(cascade=...) - as shown in the previous example. + It is recommended to use @Cascade to + compliment @*To*(cascade=...) as shown in the + previous example.
@@ -4142,7 +4046,7 @@ public class Forest { ... } Queries Since Hibernate has more features on named queries than the one - defined in the EJB3 specification, + defined in the JPA specification, @org.hibernate.annotations.NamedQuery, @org.hibernate.annotations.NamedQueries, @org.hibernate.annotations.NamedNativeQuery and @@ -4336,8 +4240,6 @@ public interface Cuisine { @Tuplizer(impl = DynamicComponentTuplizer.class) public Country getCountry(); public void setCountry(Country country); - - }
diff --git a/annotations/src/main/java/org/hibernate/annotations/AccessType.java b/annotations/src/main/java/org/hibernate/annotations/AccessType.java index 5a2037e318..833717fa56 100644 --- a/annotations/src/main/java/org/hibernate/annotations/AccessType.java +++ b/annotations/src/main/java/org/hibernate/annotations/AccessType.java @@ -34,6 +34,8 @@ import static java.lang.annotation.RetentionPolicy.RUNTIME; /** * Property Access type * + * Prefer the standard {@link javax.persistence.Access} annotation + * * @author Emmanuel Bernard */ @Target({ TYPE, METHOD, FIELD }) diff --git a/annotations/src/main/java/org/hibernate/annotations/CascadeType.java b/annotations/src/main/java/org/hibernate/annotations/CascadeType.java index d3faa10b71..0fb831c5fa 100644 --- a/annotations/src/main/java/org/hibernate/annotations/CascadeType.java +++ b/annotations/src/main/java/org/hibernate/annotations/CascadeType.java @@ -35,9 +35,11 @@ public enum CascadeType { 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 diff --git a/annotations/src/main/java/org/hibernate/annotations/CollectionOfElements.java b/annotations/src/main/java/org/hibernate/annotations/CollectionOfElements.java index ba0e68f23c..2b873aa93f 100644 --- a/annotations/src/main/java/org/hibernate/annotations/CollectionOfElements.java +++ b/annotations/src/main/java/org/hibernate/annotations/CollectionOfElements.java @@ -35,10 +35,12 @@ import static javax.persistence.FetchType.LAZY; * 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 diff --git a/annotations/src/main/java/org/hibernate/annotations/IndexColumn.java b/annotations/src/main/java/org/hibernate/annotations/IndexColumn.java index 4bd70d40f9..9a639e06cc 100644 --- a/annotations/src/main/java/org/hibernate/annotations/IndexColumn.java +++ b/annotations/src/main/java/org/hibernate/annotations/IndexColumn.java @@ -31,6 +31,7 @@ import java.lang.annotation.Target; /** * Describe an index column of a List + * Prefer the standard {@link javax.persistence.OrderColumn} annotation * * @author Matthew Inger */