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

Module 06 - Hibernate Complex 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 06 - Hibernate Complex 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/ 29

Module 06: Complex Mapping

CS544: Enterprise Architecture

© 2014 Time2Master 1
Complex Mappings
 In this module we will cover:
 Secondary tables – allow a class to be mapped to
multiple tables
 Embedded classes – allow multiple classes to be
mapped to a single table
 Composite keys – can be made using embedded
classes
 Immutable entities – Hibernate can optimize for
entities that never change

© 2014 Time2Master 2
Complex Mapping

SECONDARY TABLES

© 2014 Time2Master 3
Secondary Tables
 Secondary tables can be used anywhere to
move properties into separate table(s)
 To do so, the property has to specify the table
 Secondary tables can even be used in combination
with the Single table inheritance strategy
Secondary table used in an
@Entity inheritance hierarchy
@DiscriminatorValue("savings")
@SecondaryTable(
name="SavingsAccount",
pkJoinColumns=@PrimaryKeyJoinColumn(name="number")
)
public class SavingsAccount extends Account {
@Column(table="SavingsAccount")
private double APY;
Property specifies that it should
... be on the SavingsAccount table

© 2014 Time2Master 4
Secondary Table
@SecondaryTables can specify
multiple @SecondaryTable pkJoinColumns can be used to
@Entity specify a multi column join
@SecondaryTables(
@SecondaryTable(name="warehouse", pkJoinColumns = {
@PrimaryKeyJoinColumn(name="product_id", referencedColumnName="number")
}
))
public class Product { JoinColumn name can differ
@Id from the referenced column
@GeneratedValue
private int number;
private String name;
private BigDecimal price; Properties need to
@Column(table="warehouse") specify the secondary
private boolean available; table to be on it All you really need is @SecondaryTable
and a name, the rest is optional
... @Entity
@SecondaryTable(name="warehouse")
public class Product {
@Id
Product
@GeneratedValue
private int number;
+number
+name private String name;
+price private BigDecimal price;
+available
@Column(table = "warehouse")
private int available;

...
© 2014 Time2Master 5
XML
<hibernate-mapping package="join_tables">
<class name="Product">
<id name="number">
<generator class="native" />
</id>
<property name="name" />
<property name="price" />
<join> tag to specify the table
<join table="warehouse">
<key column="product_id" /> Requires <key> to specify
<property name="available" /> the pk join column
</join>
</class>
</hibernate-mapping>

Product Table

Product

+number
+name
+price
+available
Warehouse Table

© 2014 Time2Master 6
Complex Mapping

EMBEDDED CLASSES

© 2014 Time2Master 7
Embedded Classes
 Combine multiple classes in a single table
 Especially useful for tight associations
 These classes are considered value classes
rather than entity classes
Address is embedded
inside the Person table

Address
Person
lives at +street
+firstname +city
+lastname 1 1 +state
+zip

© 2014 Time2Master 8
Embeddable
@Embeddable
instead of @Entity
@Entity @Embeddable
public class Person { public class Address {
@Id private String street;
@GeneratedValue private String city;
private int id; private String state;
@Embedded private String zip;
private String firstname;
annotation is private String lastname;
used for ... No @Id in embeddable
embeddable @Embedded
objects private Address address;

...

Address
Person
lives at +street
+firstname +city
+lastname 1 1 +state
+zip

© 2014 Time2Master 9
XML
<hibernate-mapping package="embedded">
<class name="Person">
<id name="id">
<generator class="native" />
</id>
<property name="firstname" />
<property name="lastname" />
<component> tag indicates
<component name="address" class="Address"> an embedded object
<property name="street" />
<property name="city" />
<property name="state" />
<property name="zip" />
</component>
</class>
</hibernate-mapping>

Address
Person
lives at +street
+firstname +city
+lastname 1 1 +state
+zip

© 2014 Time2Master 10
Multiple Embedded Addresses
@Entity
public class Customer {
@Id
@GeneratedValue
private int id;
private String firstname; Rename the column names
private String lastname; for the embedded object
@Embedded
using @AttributeOverrides
@AttributeOverrides( {
@AttributeOverride(name="street", column=@Column(name="ship_street")),
@AttributeOverride(name="city", column=@Column(name="ship_city")),
@AttributeOverride(name="state", column=@Column(name="ship_state")),
@AttributeOverride(name="zip", column=@Column(name="ship_zip"))
})
private Address shipping;

@Embedded
@AttributeOverrides( {
@AttributeOverride(name="street", column=@Column(name="bill_street")),
@AttributeOverride(name="city", column=@Column(name="bill_city")),
@AttributeOverride(name="state", column=@Column(name="bill_state")),
@AttributeOverride(name="zip", column=@Column(name="bill_zip"))
})
private Address billing;

... © 2014 Time2Master

11
Multiple Addresses XML
<hibernate-mapping package="embedded">
<class name="Customer">
<id name="id">
<generator class="native" />
</id>
<property name="firstname" />
<property name="lastname" />

<component name="shipping" class="Address">


<property name="street" column="ship_street" /> You can specify the column
<property name="city" column="ship_city" /> name using the column
<property name="state" column="ship_state" /> attribute on <property>
<property name="zip" column="ship_zip" />
</component>

<component name="billing" class="Address">


<property name="street" column="bill_street" />
<property name="city" column="bill_city" />
<property name="state" column="bill_state" />
<property name="zip" column="bill_zip" />
</component>
</class>
</hibernate-mapping>

© 2014 Time2Master 12
Complex Mapping

COMPOSITE KEYS

© 2014 Time2Master 13
Composite Keys
 Composite Keys are multi-column Primary Keys
 By definition these are natural keys
 Have to be set by the application (not generated)
 Generally found in legacy systems
 Also create multi-column Foreign Keys

 There are several different mapping strategies:


 Most common mapping uses an embeddable class as
the composite key
 Other mappings are not supported by both annotations
and XML (either one or the other)

© 2014 Time2Master 14
Composite Ids
@Embeddable
@Embeddable
public class Name {
private String firstname;
private String lastname;

... Also requires hashCode and equals methods


(see next slide)

@Entity
public class Employee { Embeddable object as identifier
@EmbeddedId creates composite key
private Name name;
@Temporal(TemporalType.DATE)
private Date startDate;

...

PK is made of
Both firstname
and lastname

© 2014 Time2Master 15
equals() & hashCode()
@Embeddable
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 16
XML
<hibernate-mapping package="composite_key">
<class name="Employee">
<composite-id name="name" class="Name"> <composite-id> tag is used
<key-property name="firstname" /> in XML to specify the
<key-property name="lastname" /> property and class name
</composite-id>

<property name="startDate" type="date"/>


</class>
</hibernate-mapping>

PK is made of
Both firstname
and lastname

© 2014 Time2Master 17
Foreign Keys to Composite Ids
@Entity
public class Employee { Same Name embeddable
@EmbeddedId @Id as before
private Name name;
@Temporal(TemporalType.DATE)
private Date startDate; Normal mappedBy on this side
@OneToMany(mappedBy = "owner")
private List<Project> projects = new ArrayList<Project>();

...

@Entity
public class Project { Two column
@Id
Foreign Key
@GeneratedValue
private int id;
private String name;
@ManyToOne
@JoinColumns( {
@JoinColumn(name = "Emp_firstname", referencedColumnName = "firstname"),
@JoinColumn(name = "Emp_lastname", referencedColumnName = "lastname")
})
private Employee owner;
Two column FK
... specification

© 2014 Time2Master 18
XML Composite FK
<hibernate-mapping package="composite_key">
<class name="Employee">
<composite-id name="name" class="Name">
<key-property name="firstname" />
<key-property name="lastname" />
</composite-id>
<property name="startDate" type="date" /> Even though the collection
is inverse we still need to
<bag name="projects" inverse="true"> specify both columns
<key>
<column name="Emp_firstname" />
<column name="Emp_lastname" />
</key> Using <column> tags inside <key>
<one-to-many class="Project" /> instead of the column attribute on <key>
</bag>
</class>
</hibernate-mapping>

<hibernate-mapping package="composite_key">
<class name="Project">
<id name="id">
<generator class="native" />
</id>

<many-to-one name="owner" class="Employee">


<column name="Emp_firstname" />
<column name="Emp_lastname" />
</many-to-one> Using <column> tags inside <many-to-one>
</class> instead of the column attribute on it
</hibernate-mapping>
© 2014 Time2Master 19
Complex Mapping

ELEMENT COLLECTIONS

© 2014 Time2Master 20
Element Collections
 For collections of primitive values or
collections of embeddables

 Does not really make sense from a OO / UML


point of view

 Good to know about

© 2014 Time2Master 21
@ElementCollection
@Entity
public class Person { Optionally specify the name
@Id @GeneratedValue for the collection table
private int id;
@ElementCollection
@CollectionTable(name = "firstNames")
private List<String> givenNames = new ArrayList<>();
@ElementCollection
@CollectionTable(name = "lastNames")
private List<String> familyNames = new ArrayList<>();
@ElementCollection
private List<Address> addresses = new ArrayList<>();
...

Default table name is:


Classname_propertyname

© 2014 Time2Master 22
Map

@Entity
public class Person {
@Id @GeneratedValue
Optionally specify the name
private int id;
private String name; for the additional key column
@ElementCollection
@MapKeyColumn(name = "name")
private Map<String, Pet> Pets = new HashMap<>();
...

Default key column name is:


propertyname_KEY

© 2014 Time2Master 23
Complex Mapping

IMMUTABLE ENTITIES

© 2014 Time2Master 24
Immutable Entities
 An immutable entity is an entity that
 Once created, does not change – no updates
 Hibernate can perform several optimizations

 A Java immutable class:


 Only has getters methods, no setters
 Sets all fields in the constructor
 Gives Hibernate field access

© 2014 Time2Master 25
Immutability
@Entity
@org.hibernate.annotations.Entity(mutable=false) Set mutable false using
public class Payment { Hibernate Entity extension
@Id Field access through
@GeneratedValue placement of @Id
private final int id;
private final double amount;
@Column(name="`to`")
private final String to;
@Column(name="`from`")
private final String from;
Data is set in constructor
public Payment() {}
public Payment(double amount, String to, String from) {
this.amount = amount;
this.to = to;
this.from = from;
} Getters, but no Setters
public int getId() { return id; }
public double getAmount() { return amount; }
public String getTo() { return to; }
public String getFrom() { return from; }
}

© 2014 Time2Master 26
XML

Default Field access

<hibernate-mapping package="immutable" default-access="field">


<class name="Payment" mutable="false">
<id name="id">
<generator class="native" /> Mutable = false
</id>
<property name="amount" />
<property name="to" column="`to`" />
<property name="from" column="`from`"/> (To and From are SQL keywords)
</class>
</hibernate-mapping>

© 2014 Time2Master 27
Active Learning
 What is a value class?

 Why do we need to implement hashcode()


and equals() when using @EmbeddedId?

© 2014 Time2Master 28
Module Summary
 In this module we covered some of the more
interesting mappings possible with Hibernate
 Many of these mappings are very useful when
mapping to a legacy database
 Embeddable components also have their place
in non-legacy systems
 Allow a fine-grained object model to be mapped
to a more coarse and efficient db model
 Sacrifices some flexibility for greater efficiency

© 2014 Time2Master 29

You might also like