0% found this document useful (0 votes)
1 views

Module 04 - Hibernate Collection Mapping-upd

Uploaded by

surafelbehailu90
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
1 views

Module 04 - Hibernate Collection Mapping-upd

Uploaded by

surafelbehailu90
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 37

Module 04: Collection Mapping

CS544: Enterprise Architecture

© 2014 Time2Master 1
Collections
 Java uses collections of references to
implement the many side(s) of associations
 So far we’ve always mapped collections as bags

 There are 4 Types of collections:


 Bags, Sets, Lists, and Maps

 These 4 can be split into 2 categories


 Indexed, and non-indexed collections

© 2014 Time2Master 2
Program to Interface
 Hibernate requires you to program to
interface (P2I) for your collections
 Replaces collections with its own implementations
 P2I is also a general Java best practice
@Entity
public class Person {
@Id
@GeneratedValue
private int id; collection initialized
private String firstname; right away
private String lastname;
@OneToMany
private List<Car> cars = new ArrayList();

...
Interface
Hibernate replaces ArrayList with its own
List implementation once the collection
has been retrieved or persisted

© 2014 Time2Master 3
Collection Mapping

COLLECTION: BAG

© 2014 Time2Master 4
Bags
 The most basic collection is a bag
 A bag has no inherent order
 A bag can contain duplicates

 People often own a ‘bag’ of hardware tools


 No inherent order
 May contain duplicate tools

© 2014 Time2Master 5
Bag Implementation
 java.util.Collection is a bag interface
 Java has no official bag implementation

 Bags are non-indexed collections


 A relational database can implement a bag using
only a Foreign Key, no additional index
Person Tool
owns
+firstname +type
+lastname 1 0..* +size

Implemented with a
single foreign key

© 2014 Time2Master 6
Mapping a Bag
 java.util.Collection maps as a Bag
@Entity
public class Person {
@Id
@GeneratedValue
private int id;
private String firstname;
private String lastname;
@OneToMany(mappedBy="owner", cascade=CascadeType.PERSIST)
private Collection<Tool> tools = new ArrayList();

...
Hibernate will map a We use an ArrayList since
Collection as a Bag there is no official java
Bag implementation
@Entity
public class Tool { We’ve mapped this Person Tool
owns
@Id collection as a bi- +firstname +type
+lastname 1 0..* +size
@GeneratedValue directional one to many
private int id;
private String type;
private String size;
@ManyToOne
private Person owner;

...
© 2014 Time2Master 7
Mapping a Bag
 By default java.util.List maps as a Bag
@Entity
public class Person {
@Id
@GeneratedValue
private int id;
private String firstname;
private String lastname;
@OneToMany(mappedBy="owner", cascade=CascadeType.PERSIST)
private List<Tool> tools = new ArrayList();

...
By default List also ArrayList is the
maps to a Bag most common List
implementation
@Entity
public class Tool { Person Tool
owns
@Id Same bi-directional one +firstname +type
+lastname 1 0..* +size
@GeneratedValue to many as last slide
private int id;
private String type;
private String size;
@ManyToOne
private Person owner;

...
© 2014 Time2Master 8
Bag XML
The XML bag mappings for
<hibernate-mapping package="bag_collection"> java.util.Collection and
<class name="Person" >
java.util.List are the same
<id name="id">
<generator class="native"/>
Only the </id>
name <property name="firstname" /> Use the <bag> tag to map bag
<property name="lastname" />
attribute <bag name="tools" inverse="true" access="field" cascade="persist">
is required <key column="owner_id" />
<one-to-many class="Tool"/>
</bag> <key> and an
</class> association tag
</hibernate-mapping> are required

<hibernate-mapping package="bag_collection">
<class name="Tool" >
<id name="id"> For the sake of completeness: the
<generator class="native"/> other side of the bi-directional one
</id> to many association
<property name="type" />
<property name="size" />
<many-to-one name="owner" column="owner_id" class="Person" />
</class>
</hibernate-mapping>

© 2014 Time2Master 9
Collection Mapping

COLLECTION: SET

© 2014 Time2Master 10
Sets
 Sets are bags that can not contain duplicates:
 A set still has no inherent order
 A set can not contain duplicates

 Store bought toolboxes are generally a set


 No duplicates
 No inherent order*

© 2014 Time2Master 11
Set Implementation
 Java has the java.util.Set interface
 java.util.HashSet is the general implementation

 Like bags, sets are non-indexed collections


 A set can be implemented using a Foreign Key, no
additional index
Toolbox Tool
contains
+manufacturer +type
1 1..* +size

Foreign key

© 2014 Time2Master 12
equals() & hashCode()
@Entity
public class Name {
private String firstname;
private String lastname;

...
Compares object
public boolean equals(Object obj) { contents for equality
if (this == obj)
return true;
if ((obj == null) || obj.getClass() != this.getClass())
return false;
Name n = (Name) obj;
if (firstname == n.firstname || (firstname != null && firstname.equals(n.firstname))
&& lastname == n.lastname || (lastname != null && lastname.equals(n.lastname))) {
return true;
} else {
return false;
}
}
Generates an int based on
public int hashCode() { the class contents
int hash = 1234;
if (firstname != null)
hash = hash + firstname.hashCode();
if (lastname != null)
hash = hash + lastname.hashCode();
return hash;
}
© 2014 Time2Master 13
Mapping a Set
 java.util.Set maps as a Set
@Entity
public class Toolbox {
@Id
@GeneratedValue
private int id;
private String manufacturer;
private String model;
@OneToMany(mappedBy="toolbox", cascade=CascadeType.PERSIST)
private Set<Tool> tools = new HashSet();
...
Set maps as a set HashSet is the
most common Set
implementation
@Entity
public class Tool {
Tool class completes the Toolbox Tool
@Id contains
@GeneratedValue bi-directional many to one +manufacturer +type
1 1..* +size
private int id;
private String type;
private String size;
@ManyToOne
private Toolbox toolbox;

...
© 2014 Time2Master 14
Set XML
<hibernate-mapping package="set">
<class name="Toolbox" >
<id name="id"> Only difference between
<generator class="native"/> mapping a set and a bag is
</id> in the tag name <set>
<property name="manufacturer" />
<set name="tools" inverse="true" access="field" cascade="persist">
<key column="toolbox_id" />
<one-to-many class="Tool"/>
</set> As with the bag mapping
</class> <key> and an association
</hibernate-mapping>
tag are required

<hibernate-mapping package="set">
<class name="Tool" >
<id name="id">
<generator class="native"/>
</id>
<property name="type" />
<property name="size" />
<many-to-one name="toolbox" column="toolbox_id" class="Toolbox" />
</class>
</hibernate-mapping>

© 2014 Time2Master 15
Collection Mapping

COLLECTION: MAP

© 2014 Time2Master 16
Maps
 A Map ‘maps’ a set of keys to a bag of values:
 Each value in the bag has a unique key
 Given a key, the map can quickly retrieve the value
 No inherent order in either keys or values

 Pet owner ship can be modeled as a map.


 Each pet has a unique name*
 To find a pet, you use its name
 No inherent order in names or pets

© 2014 Time2Master 17
Map Implementation
 Java has the java.util.Map interface
 Java.util.HashMap is the most common map

 Maps are indexed collections


 They need a foreign key and an additional column
for the keys which also needs to be indexed
Pet
Person
owns +name
+firstname +species
+lastname +race
1 0..*

Name is also indexed

Foreign key

© 2014 Time2Master 18
Map Mapping Issues
 There are two types of map mappings:
1. The key is already part of the value entity class
 E.g. name is already part of the Pet class
2. The key is not part of the value entity class
 The key index column becomes an additional column,
just like the index column for a list
 Mapping issues similar to List (coming up)

Pet
Person Person Pet
owns +name owns
+firstname +species +firstname +species
+lastname +race +lastname +race
1 0..* 1 0..*

Name
already Added
there Name
column
© 2014 Time2Master 19
Key is part of the Entity Class
@Entity
public class Person {
@Id
@GeneratedValue
private int id;
@MapKey private String firstname; Normal @OneToMany
specifies the private String lastname;
key column @OneToMany(mappedBy="owner", cascade=CascadeType.PERSIST)
on the @MapKey(name="name")
private Map<String, Pet> pets = new HashMap();
remote class
...

@Entity
public class Pet {
Person Pet
@Id owns
+firstname +species
@GeneratedValue Specified by @MapKey, +lastname +race
1 0..*
private int id; will be indexed +name
private String name;
Normal private String species;
@ManyToOne private String race;
@ManyToOne
private Person owner;
...

© 2014 Time2Master 20
XML
<hibernate-mapping package="map">
<class name="Person" >
<id name="id">
<generator class="native"/>
</id>
<property name="firstname" /> <map> similar to <bag> and <set>
<property name="lastname" />
<map name="pets" access="field" cascade="persist" inverse="true">
<key column="owner_id" />
<map-key type="string" column="name"/>
<one-to-many class="Pet"/> <map-key> specifies the key
</map> column on the remote table
</class>
</hibernate-mapping>

<hibernate-mapping package="map">
<class name="Pet">
<id name="id">
<generator class="native" />
</id>
<property name="name" />
<property name="species" />
Regular <many-to-one>
<property name="race" />
<many-to-one name="owner" column="owner_id" class="Person" />
</class>
</hibernate-mapping>
© 2014 Time2Master 21
Map – Separate Key
@Entity
public class Person {
@Id
@GeneratedValue
private int id; @OneToMany is
private String firstname; the owning side
@JoinColumn private String lastname; @MapKeyColumn
and its name @OneToMany(cascade = CascadeType.PERSIST) defaults to not nullable
attribute are @JoinColumn(name="owner_id") - >insertion problems
@MapKeyColumn(name="name", nullable=true)
required
private Map<String, Pet> pets = new HashMap();

...

@Entity
public class Pet {
@Id False updateble and
@ManyToOne @GeneratedValue
insertable on
does not have private int id;
private String species; @JoinColumn
a mappedBy instead of mappedBy
private String race;
attribute @ManyToOne
@JoinColumn(name="owner_id", updatable=false, insertable=false)
private Person owner;

...

© 2014 Time2Master 22
Separate Key XML
<hibernate-mapping package="map_seperateKey">
<class name="Person" >
<id name="id">
<generator class="native"/>
</id>
<property name="firstname" />
<property name="lastname" /> Map side is the owning
<map name="pets" access="field" cascade="persist" > side (no inverse)
<key column="owner_id" />
<map-key type="string" column="name" />
<one-to-many class="Pet"/>
</map> When <map-key> specifies a
</class> non-existing column Hibernate
</hibernate-mapping> will add it as the key column

<hibernate-mapping package="map_seperateKey">
<class name="Pet"> <many-to-one> does not
<id name="id">
have an inverse attribute
<generator class="native" />
</id> to specify that it is not
<property name="species" /> the owning side
<property name="race" />
<many-to-one name="owner" column="owner_id" class="Person"
insert="false" update="false" />
</class> Uses insert and update false instead
</hibernate-mapping> to emulate inverse behavior
© 2014 Time2Master 23
Collection Mapping

COLLECTION: LIST

© 2014 Time2Master 24
Lists
 Lists are bags with an inherent order:
 A List has an inherent, arbitrary order
 A List can still contain duplicates

 A shopping list is a typical list example


 An inherent, although often arbitrary order
 May contain duplicates

© 2014 Time2Master 25
List Implementation
 Java has the java.util.List interface
 Java.util.ArrayList is the most common list

 Lists are indexed collections


 A List needs an additional indexed sequence
column to maintain its sequence
Person Item
needs to buy
+firstname +name
+lastname +description
1 0..*

Foreign key

Additional indexed column


to maintain sequence
© 2014 Time2Master 26
Incorrectly Mapped
One to Many bi-directional List
@Entity
public class Person {
@Id
@GeneratedValue
private int id;
private String firstname;
private String lastname;
@OneToMany(mappedBy="buyer",cascade=CascadeType.PERSIST)
@OrderColumn(name="sequence") @OrderColumn specifies
private List<Item> shopList = new ArrayList(); the additional column on
the Item table
How you would expect
... to
map it, but it doesn’t work

@Entity
public class Item {
@Id
@GeneratedValue
private int id;
private String name;
private String description;
@ManyToOne Normal @ManyToOne
private Person buyer;

...

© 2014 Time2Master 27
Hibernate List Mapping Issues
 List side needs to be the owning side
 Bi-directional problems:
 In a bi-directional one to many, the side without
the Foreign Key needs to be the owning side
 In a bi-directional many to many with two lists,
both will have to be ‘owner’ (2 uni != bi-direct)
Person Item
needs to buy
+firstname +name
+lastname +description
1 0..*
Although the
Foreign key is
on the other
side, Person will Foreign key
need to be the
owning side
Additional indexed column
to maintain sequence
© 2014 Time2Master 28
One to Many bi-directional List
@Entity
public class Person {
@Id
@GeneratedValue
private int id; @OneToMany is
private String firstname; the owning side
@JoinColumn private String lastname;
and its name @OneToMany(cascade=CascadeType.PERSIST)
attribute are @JoinColumn(name="buyer_id")
@OrderColumn(name="sequence")
required (Why?)
private List<Item> shopList = new ArrayList();

...

@Entity
public class Item {
@Id Updateble and
@ManyToOne @GeneratedValue
insertable false on
does not have private int id;
private String name; @JoinColumn to
a mappedBy emulate mappedBy
private String description;
attribute @ManyToOne
@JoinColumn(name="buyer_id", updatable=false, insertable=false)
private Person buyer;

...

© 2014 Time2Master 29
List XML
<hibernate-mapping package="list">
<class name="Person" >
<id name="id">
<generator class="native"/>
</id>
<property name="firstname" /> <list> is similar to <bag> and <set>
<property name="lastname" />
<list name="shopList" access="field" cascade="persist"> List side is the owning
<key column="buyer_id"/>
<list-index column="sequence"/>
side (no inverse)
<one-to-many class="Item"/>
</list> Also requires a <list-index>
</class> tag not just a <key> and an
</hibernate-mapping> association tag

<hibernate-mapping package="list">
<class name="Item"> <many-to-one> does not
<id name="id">
have an inverse attribute
<generator class="native" />
</id> to specify that it is not
<property name="name" /> the owning side
<property name="description" />
<many-to-one name="buyer" column="buyer_id" class="Person"
insert="false" update="false" />
</class> Uses insert and update
</hibernate-mapping> false instead of inverse
© 2014 Time2Master 30
Collection Mapping

ORDER BY

© 2014 Time2Master 31
Order By
 Hibernate can add an ‘ORDER BY’ SQL clause
when retrieving a collection
 Sets, bags, and maps can be ordered in this way,
the order is done by the database
 Collections mapped as list can not be re-ordered,
they already have a specific order
@Entity
public class Toolbox {
@Id
@GeneratedValue
private int id;
private String manufacturer;
private String model;
@OneToMany(mappedBy="toolbox", cascade=CascadeType.PERSIST)
@OrderBy("size ASC")
private Set<Tool> tools = new HashSet<Tool>();

Tools set will be ordered


... by
size ascending
© 2014 Time2Master 32
Ordered Bag Example
@Entity @Entity
public class Person { public class Tool {
Will be
@Id @Id ordered by
@GeneratedValue @GeneratedValue type desc
private int id; private int id;
private String firstname; private String type;
private String lastname; private String size;
@OneToMany(mappedBy="owner", cascade=CascadeType.PERSIST) @ManyToOne
@OrderBy("type DESC") private Person owner;
private List<Tool> tools = new ArrayList<Tool>(); Order tools by
‘type DESC’ ...
...
java.util.List persisted as a bag

<hibernate-mapping package="bag_collection">
<class name="Person" >
<id name="id">
<generator class="native"/>
</id>
<property name="firstname" />
<property name="lastname" />
<bag name="tools" inverse="true" access="field" cascade="persist“ order-by="type ASC">
<key column="owner_id" />
<one-to-many class="Tool"/>
</bag>
In XML <bag>, <set>,
</class> and <map> can specify
</hibernate-mapping> the order-by attribute

© 2014 Time2Master 33
Collection Mapping

WRAPPING UP

© 2014 Time2Master 34
Mapping Tip
 Recommend always creating accessor
convenience methods
 Not just for bi-directional associations

Person Car
@Entity owns
public class Person { +firstname +year
+lastname +model
@Id 1 0..*
+cars +maker
@GeneratedValue
private int id;
private String firstname; Uni-directional one-to-many
private String lastname;
@OneToMany
private List<Car> cars = new ArrayList<Car>();

...

public boolean addCar(Car car) { return cars.add(car); }


public boolean removeCar(Car car) { return cars.remove(car); }
}

Uni-directional convenience methods

© 2014 Time2Master 35
Active Learning
 What does it mean to have inherent order?

 What are the characteristics of a Map?

© 2014 Time2Master 36
Module Summary
 We’ve covered the following collections:
 Bags – Allow duplicates, no guaranteed order, but can
be ordered by Hibernate
 Sets – Do not allow duplicates, no guaranteed order,
can be ordered by Hibernate
 Lists – Allow duplicates, a guaranteed order by using
an additional index column in the db
 Maps – Link a set of keys to a bag of values, by having
an (additional) key that is used as key
 Default to using bags, use other types as needed

© 2014 Time2Master 37

You might also like