Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
1 views

Module 04 - Hibernate Collection Mapping-upd

Uploaded by

surafelbehailu90
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
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
We take content rights seriously. If you suspect this is your content, claim it here.
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