diff --git a/reference/en/modules/collection_mapping.xml b/reference/en/modules/collection_mapping.xml index 9fb74badd5..261c8cbb78 100644 --- a/reference/en/modules/collection_mapping.xml +++ b/reference/en/modules/collection_mapping.xml @@ -1,141 +1,102 @@ Collection Mapping - - Persistent Collections - + + Persistent collections + - This section does not contain much example Java code. We assume you already know - how to use Java's collections framework. If so, there's not really anything more - to know - with a single caveat, you may use Java collections the same way you - always have. + Hibernate requires that persistent collection-valued fields be declared + as an interface type, for example: - + + + - Hibernate can persist instances of - java.util.Map, - java.util.Set, - java.util.SortedMap, - java.util.SortedSet, - java.util.List, - and any array of persistent entities or values. Properties of type - java.util.Collection or - java.util.List - may also be persisted with "bag" semantics. + The actual interface might be java.util.Set, + java.util.Collection, java.util.List, + java.util.Map, java.util.SortedSet, + java.util.SortedMap or ... anything you like! (Where + "anything you like" means you will have to write an implementation of + org.hibernate.usertype.UserCollectionType.) - + - Now the caveat: persistent collections do not retain any extra semantics added by the class - implementing the collection interface (eg. iteration order of a LinkedHashSet). - The Java type of a property holding a collection must be the interface type: Map, - Set, List, or simply Collection; never - HashMap, TreeSet or ArrayList. This - restriction exists because, when you're not looking, Hibernate sneakily replaces your instances - of Map, Set and List with instances - of its own persistent implementations of Map, Set, or - List. (So also be careful when using == on your collections.) + Notice how we initialized the instance variable with an instance of + HashSet. This is the best way to initialize collection + valued properties of newly instantiated (non-persistent) instances. When + you make the instance persistent - by calling create(), + for example - Hibernate will actually replace the HashSet + with an instance of Hibernate's own implementation of Set. + Watch out for errors like this: - - - You may therefore initialize a collection in your class with whatever implementation - you find compatible. The persistent collections injected by Hibernate behave like - HashMap, - HashSet, - TreeMap, - TreeSet and - ArrayList - respectively. Of course, this depends on the mapping style you chose (ie. ordered or - not, preserving position of elements, allowing duplicates, etc). - - + - Collections (not the contents) obey the usual rules for value types: no shared - references, created and deleted along with the owning entity. Due to the underlying - relational model, they do not support null value semantics; Hibernate does not - distinguish between a null collection reference and an empty collection. + The persistent collections injected by Hibernate behave like + HashMap, HashSet, + TreeMap, TreeSet or + ArrayList, depending upon the interface type. - Collections are automatically persisted when referenced by a persistent object - and automatically deleted when unreferenced. If a collection is passed from one + Collections instances have the usual behavior of value types. They are + automatically persisted when referenced by a persistent object and + automatically deleted when unreferenced. If a collection is passed from one persistent object to another, its elements might be moved from one table to - another. You shouldn't have to worry much about any of this. Just use - Hibernate's collections the same way you use ordinary Java collections, but - make sure you understand the semantics of bidirectional associations (discussed - later) before using them. + another. Two entities may not share a reference to the same collection + instance. Due to the underlying relational model, collection-valued properties + do not support null value semantics; Hibernate does not distinguish between + a null collection reference and an empty collection. - Collection instances are distinguished in the database by a foreign key to - the owning entity. This foreign key is referred to as the - collection key , on the table holding the collection elements. - The collection key is mapped by the <key> element. If you - have a foreign-key constraint set in the database, and have chosen the - ON DELETE CASCADE option, always use the - on-delete attribute on your <key> - mappings: - - - ]]> - - - Collections may contain almost any other Hibernate type, including all basic types, - custom types, components, and of course, references to other entities. This is an - important definition: An object in a collection can either be handled with "pass by - value" semantics (it therefore fully depends on the collection owner) or it can be a - reference to another entity, with its own lifecycle. In this case, only the "link" - between two objects is stored in the collection (non-Java developers call these links - "pointers"). Collections may not contain other collections. The contained type - is referred to as the collection element type. Collection elements - are mapped by <element>, <composite-element>, - or in the case of entity references, with <one-to-many>, - <many-to-many>, or <many-to-any>. - The first two map elements with value semantics, the other three are used to map - entity associations. - - - - All collection mappings, except those with set and bag semantics, need an - index column in the collection table - a column that maps to an - array index, or List index, or Map key. The - index of a Map may be of any basic type, it may be an entity reference, - or even a composite type (it may not be a collection). The index of an array or list is - always of type integer. Indexes are mapped using - <index>, <index-many-to-many>, - <composite-index>, or <index-many-to-any>. - - - - There are quite a range of mappings that can be generated for collections, - covering many common relational models. We suggest you experiment with the - schema generation tool to get a feeling for how various mapping declarations - translate to database tables. + You shouldn't have to worry much about any of this. Use persistent collections + the same way you use ordinary Java collections. Just make sure you understand + the semantics of bidirectional associations (discussed later). - Mapping a Collection + Collection mappings - Collections are declared by the - <set>, - <list>, - <map>, - <bag>, - <array> and - <primitive-array> elements. - <map> is representative: + The Hibernate mapping element used for mapping a collection depends upon + the type of the interface. For example, a <set> + element is used for mapping properties of type Set. + + + + + + + + +]]> + + + Apart from <set>, there is also + <list>, <map>, + <bag>, <array> and + <primitive-array> mapping elements. The + <map> element is representative: @@ -169,7 +130,7 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set > - + ]]> @@ -251,88 +212,105 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set - The mapping of a List or array requires a seperate table column holding the array - or list index (the i in foo[i]). If your relational model doesn't - have an index column, e.g. if you're working with legacy data, use an unordered Set - instead. This seems to put people off who assume that List should just be a more - convenient way of accessing an unordered collection. Hibernate collections strictly obey the actual - semantics attached to the Set, List and Map - interfaces. List elements don't just spontaneously rearrange themselves! - - - - On the other hand, people who planned to use the List to emulate - bag semantics have a legitimate grievance here. - A bag is an unordered, unindexed collection which may contain the same element multiple times. - The Java collections framework lacks a Bag interface, hence you have to emulate - it with a List. Hibernate lets you map properties of type List - or Collection with the <bag> element. Note that bag - semantics are not really part of the Collection contract and they actually - conflict with the semantics of the List contract (however, you can sort - the bag arbitrarily, discussed later in this chapter). - - - - Note: Large Hibernate bags mapped with inverse="false" are inefficient and - should be avoided; Hibernate can't create, delete or update rows individually, because there is - no key that may be used to identify an individual row. - - - - - - Collections of Values and Many-To-Many Associations - - - A collection table is required for any collection of values and any collection of - references to other entities mapped as a many-to-many association (the natural semantics - for a Java collection). The table requires (foreign) key column(s), element column(s) and - possibly index column(s). - - - - The foreign key from the collection table to the table of the owning class is - declared using a <key> element. + Collection instances are distinguished in the database by the foreign key of + the entity that owns the collection. This foreign key is referred to as the + collection key column (or columns) of the collection + table. The collection key column is mapped by the <key> + element. + + + Collection foreign keys + + + There may be a nullability constraint on the foreign key column. For most + collections, this is implied. For unidirectional one to many associations, + the foreign key column is nullable by default, so you might need to specify + not-null="true". + + + ]]> + + + The foreign key constraint may use ON CASCADE DELETE. + + + ]]> + + + + + Collection elements + + + Collections may contain almost any other Hibernate type, including all basic types, + custom types, components, and of course, references to other entities. This is an + important distinction: an object in a collection might be handled with "value" + semantics (it's lifecycle fully depends on the collection owner) or it might be a + reference to another entity, with its own lifecycle. In the latter case, only the + "link" between the two objects is considered to be state held by the collection. + + + + The contained type is referred to as the collection element type. + Collection elements are mapped by <element> or + <composite-element>, or in the case of entity references, + with <one-to-many> or <many-to-many>. + The first two map elements with value semantics, the next two are used to map entity + associations. + + + + + + Indexed collections + + + All collection mappings, except those with set and bag semantics, need an + index column in the collection table - a column that maps to an + array index, or List index, or Map key. The + index of a Map may be of any basic type, mapped with + <map-key>, it may be an entity reference mapped with + <map-key-many-to-many>, or it may be a composite type, + mapped with <composite-map-key>. The index of an array or + list is always of type integer and is mapped using the + <list-index> element. The mapped column contains + sequential integers numbered from zero. Make sure that your index really starts + from zero if you have to deal with legacy data. + - + - ]]> + ]]> - + - column (required): The name of the foreign key column. + column_name (required): The name of the column holding the + collection index values. - - For indexed collections like maps and lists, we require an <index> - element. For lists, this column contains sequential integers numbered from zero. Make sure - that your index really starts from zero if you have to deal with legacy data. For maps, - the column may contain any values of any Hibernate type. - - - - + + - ]]> + type="type_name" + length="N"/>]]> - + column (required): The name of the column holding the collection index values. - + type (optional, defaults to integer): The type of the collection index. @@ -341,17 +319,12 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set - - Alternatively, a map may be indexed by objects of entity type. We use the - <index-many-to-many> element. - - - ]]> @@ -371,6 +344,32 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set + + + If your table doesn't have an index column, and you still wish to use List + as the property type, you should map the property as a Hibernate bag. + A bag does not retain its order when it is retrieved from the database, but it may be + optionally sorted or ordered. + + + + + + There are quite a range of mappings that can be generated for collections, covering + many common relational models. We suggest you experiment with the schema generation tool + to get a feeling for how various mapping declarations translate to database tables. + + + + Collections of values and many-to-many associations + + + Any collection of values or many-to-many association requires a dedicated + collection table with a foreign key column or columns, + collection element column or columns and possibly + an index column or columns. + + For a collection of values, we use the <element> tag. @@ -383,6 +382,10 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set ]]> @@ -400,8 +403,8 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set - A collection of entity references, where the references are held in a separate table - corresponds to the relational notion of many-to-many association. + A many-to-many association is specified using the + <many-to-many> element. @@ -439,8 +442,8 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set but also with this attribute on the <many-to-many> nested element. - + unique (optional): Enable the DDL generation of a unique constraint for the foreign-key column. This makes the association multiplicity @@ -454,9 +457,9 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set Some examples, first, a set of strings: - - - + + + ]]> @@ -464,9 +467,9 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set order-by attribute): - - - + + + ]]> @@ -474,19 +477,24 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set the entities are lifecycle objects, cascade="all"): - - - - + + + + ]]> A map from string indices to dates: - + - + ]]> @@ -494,34 +502,29 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set A list of components (discussed in the next chapter): - - - - - - - + + + + + + + ]]> - + - - One-To-Many Associations + + One-to-many associations A one to many association links the tables of two classes - directly, with no intervening collection table. - (This implements a one-to-many relational model.) This - relational model loses some of the semantics of Java collections: + via a foreign key, with no intervening collection table. This mapping loses + certain semantics of normal Java collections: - - - No null values may be contained in a map, set or list - - An instance of the contained entity class may not belong to more than @@ -537,15 +540,10 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set - An association from Foo to Bar requires the - addition of a key column and possibly an index column to the table of the contained - entity class, Bar. These columns are mapped using the - <key> and <index> elements - described above. - - - - The <one-to-many> tag indicates a one to many association. + An association from Product to Part requires + existence of a foreign key column and possibly an index column to the Part + table. A <one-to-many> tag indicates that this is a one to many + association. @@ -563,16 +561,7 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set - - - Example: - - - - - -]]> - + Notice that the <one-to-many> element does not need to declare any columns. Nor is it necessary to specify the table @@ -580,33 +569,39 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set - Very Important Note: If the <key> - column of a <one-to-many> association is declared - NOT NULL, Hibernate may cause constraint violations - when it creates or updates the association. To prevent this problem, - you must use a bidirectional association with the many valued - end (the set or bag) marked as inverse="true". - See the discussion of bidirectional associations later in this chapter. + Very important note: If the foreign key column of a + <one-to-many> association is declared NOT NULL, + you must declare the <key> mapping + not-null="true" or use a bidirectional association + with the collection mapping marked inverse="true". See the discussion + of bidirectional associations later in this chapter. + + - - Sorted Collections + + Advanced collection mappings + + + Sorted collections Hibernate supports collections implementing java.util.SortedMap and java.util.SortedSet. You must specify a comparator in the mapping file: - + - + ]]> @@ -626,8 +621,8 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set order-by attribute of set, bag or map mappings. This solution is only available under JDK 1.4 or higher (it is implemented using LinkedHashSet or - LinkedHashMap). This performs the ordering in the SQL query, not in - memory. + LinkedHashMap). This performs the ordering in the SQL query, + not in memory. @@ -637,7 +632,7 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set - + ]]> @@ -647,15 +642,157 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set - Associations may even be sorted by some arbitrary criteria at runtime using a + Associations may even be sorted by some arbitrary criteria at runtime using a collection filter(). - + - + - + + Bidirectional associations + + + A bidirectional association allows navigation from both + "ends" of the association. Two kinds of bidirectional association are + supported: + + + + one-to-many + + + set or bag valued at one end, single-valued at the other + + + + + many-to-many + + + set or bag valued at both ends + + + + + + + + + You may specify a bidirectional many-to-many association simply by mapping two + many-to-many associations to the same database table and declaring one end as + inverse (which one is your choice, but it can not be an + indexed collection). + + + + Here's an example of a bidirectional many-to-many association; each category can + have many items and each item can be in many categories: + + + + + ... + + + + + + + + + ... + + + + + + +]]> + + + Changes made only to the inverse end of the association are not + persisted. This means that Hibernate has two representations in memory for every + bidirectional association, one link from A to B and another link from B to A. This + is easier to understand if you think about the Java object model and how we create + a many-to-many relationship in Java: + + + + + + The non-inverse side is used to save the in-memory representation to the database. + + + + You may define a bidirectional one-to-many association by mapping a one-to-many association + to the same table column(s) as a many-to-one association and declaring the many-valued + end inverse="true". + + + + + .... + + + + + + + + + .... + +]]> + + + Mapping one end of an association with inverse="true" doesn't + affect the operation of cascades, these are orthogonal concepts! + + + + + + Ternary associations + + + There are three possible approaches to mapping a ternary association. One is to use a + Map with an association as its index: + + + + + + +]]> + + + + + +]]> + + + A second approach is to simply remodel the association as an entity class. This + is the approach we use most commonly. + + + + A final alternative is to use composite elements, which we will discuss later. + + + + + <literal>Using an <idbag></literal> @@ -701,164 +838,23 @@ kittens = cat.getKittens(); // Okay, kittens collection is a Set strategy is not supported for <idbag> collection identifiers. - - - - Bidirectional Associations - - - A bidirectional association allows navigation from both - "ends" of the association. Two kinds of bidirectional association are - supported: - - - - one-to-many - - - set or bag valued at one end, single-valued at the other - - - - - many-to-many - - - set or bag valued at both ends - - - - - - - - - Please note that Hibernate does not support bidirectional one-to-many associations - with an indexed collection (list, map or array) as the "many" end, you have to - use a set or bag mapping. - - - - You may specify a bidirectional many-to-many association simply by mapping two - many-to-many associations to the same database table and declaring one end as - inverse (which one is your choice, but it can not be an - indexed collection). - - - - Here's an example of a bidirectional many-to-many association; each category can - have many items and each item can be in many categories: - - - - - ... - - - - - - - - - ... - - - - - - -]]> - - - Changes made only to the inverse end of the association are not - persisted. This means that Hibernate has two representations in memory for every - bidirectional association, one link from A to B and another link from B to A. This - is easier to understand if you think about the Java object model and how we create - a many-to-many relationship in Java: - - - - - - The non-inverse side is used to save the in-memory representation to the database. - We would get an unneccessary INSERT/UPDATE and probably even a foreign key violation - if both would trigger changes! - - - - The same is of course also true for bidirectional one-to-many associations. You may - map a bidirectional one-to-many association by mapping a one-to-many association - to the same table column(s) as a many-to-one association and declaring the many-valued - end inverse="true". - - - - - .... - - - - - - - - - .... - -]]> - - - Mapping one end of an association with inverse="true" doesn't - affect the operation of cascades, both are different concepts! - + - - - Ternary Associations + + + + Collection examples @@ -886,24 +882,24 @@ public class Parent { }]]> - has a collection of eg.Child instances. If each - child has at most one parent, the most natural mapping is a one-to-many - association: + has a collection of Child instances. If each + child has at most one parent, the most natural mapping is a + one-to-many association: - + - + - + @@ -927,22 +923,22 @@ alter table child add constraint childfk0 (parent_id) references parent]]> - + - + - + - + ]]> @@ -958,6 +954,33 @@ create table child ( id bigint not null parent_id bigint not null ) alter table child add constraint childfk0 (parent_id) references parent]]> + + Alternatively, if you absolutely insist that this association should be unidirectional, + you can declare the NOT NULL constraint on the <key> + mapping: + + + + + + + + + + + + + + + + + + + + + +]]> + On the other hand, if a child might have multiple parents, a many-to-many association is appropriate: @@ -965,17 +988,17 @@ alter table child add constraint childfk0 (parent_id) references parent]]> - + - + - + @@ -1000,6 +1023,11 @@ alter table childset add constraint childsetfk1 (child_id) references child]]>. + + + Even more exotic association mappings are possible, we will catalog all possibilities + in the next chapter. +