Module 01: Entity Mapping
CS544: Enterprise Architecture
© 2014 Time2Master 1
Entity Class Mapping
Entity classes can be thought of as the distinct
business concepts in a domain driven design
We will start with the basic Java class
requirements for persisting entity classes
After which we will go into identity mapping,
mapping data types, and Hibernate access
We will provide both XML and annotation
mapping examples for each subject we cover
Person
+name
© 2014 Time2Master 2
Class Requirements
Hibernate requires that entity classes have:
A field that can be used as identifier
A default constructor
Getter and Setter Methods for all properties
package intro; An identifier
public class Person {
private long id;
private String name; A default constructor
public Person() {}
public Person(String name) { this.name = name; }
public long getId() { return id; }
public void setId(long id) { this.id = id; } Getter and Setter Methods
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
© 2014 Time2Master 3
About Annotations
Most of the mapping annotations we will use
are part of the Java Persistence API (JPA)
@Entity(name="MY_PERSON") Person class with
public class Person { JPA Annotations
@Id
@Column(name="PERSON_ID")
private long id;
@Column(name="FULLNAME")
private String name;
...
JPA is supported by many Java persistence
frameworks as a standard, portable API
© 2014 Time2Master 4
Hibernate Annotations
Additional Hibernate specific functionality can
be exposed using Hibernate annotations
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity Full org.hibernate.annotations
public class Person { pacakge name to clearly
@Id distinguish from JPA
@GeneratedValue
private long id;
@org.hibernate.annotations.AccessType("property")
private String name;
...
Best practice to use full package name for
hibernate annotations to clearly distinguish
from JPA
© 2014 Time2Master 5
Annotation based Mapping
@Entity Map class to ‘MY_PERSON’ table Table: MY_PERSON
@Table(name="MY_PERSON")
public class Person {
@Id Map to PERSON_ID column
@Column(name="PERSON_ID")
private long id;
@Column(name="FULLNAME")
Map to FULLNAME column
private String name;
public Person() {}
public Person(String name) { this.name = name; }
public long getId() { return id; }
private void setId(long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
Defaults to ‘Person’ table
@Entity Table: PERSON
public class Person {
@Id
Defaults to ‘id’ column
private long id; name (same as property)
private String name;
... No annotation needed, persisted
to the ‘name’ column by default
© 2014 Time2Master 6
Hibernate XML Mapping
Person.hbm.xml
Usually in the same package as Person.java
<?xml version="1.0" encoding="UTF-8"?> Table: MY_PERSON
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
<class> tag to map Person>
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"
to the `MY_PERSON’ table
<hibernate-mapping>
<class name="intro.Person" table="MY_PERSON">
<id name="id" column="PERSON_ID" />
<id> tag to map the primary key
<property name="name" column="FULLNAME" />
</class>
</hibernate-mapping> <property> tag to map
normal properties
<hibernate-mapping> Table: PERSON
<class name="intro.Person">
<id name="id" />
<property name="name" />
</class>
</hibernate-mapping> Unlike annotations, you have
to specify all properties!
© 2014 Time2Master 7
Entity Class Mapping:
MAPPING IDENTITY
© 2014 Time2Master 8
Primary key
A primary key is
Unique
No duplicate values
Constant
Value never changes
Required
Value can never be null
Primary key types:
Natural key
Has a meaning in the business domain
Surrogate key
Has no meaning in the business domain
Best practice
© 2014 Time2Master 9
Mapping Primary Keys
Object / Relational mismatch
Hibernate requires you to specify the property
that will map to the primary key
Prefer surrogate keys
Natural keys often lead to a brittle schema
@Entity @Entity Instead use id as a
public class Person { public class Person {
surrogate key for Person
@Id @Id
private String name; private long id;
private String name;
...
Name as a natural ...
primary key for Person
can give problems
© 2014 Time2Master 10
Generating Identity
Generated identity values
Ensure identity uniqueness
Private setId() methods
Ensure identity immutability
@Entity
public class Person {
@Id
@GeneratedValue Id is generated
private long id;
private String name;
public Person() {}
public Person(String name) { this.name = name; }
public long getId() { return id; } Id can not be set by
private void setId(long id) { this.id = id; } the application
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
© 2014 Time2Master 11
Generation Strategies
Hibernate JPA Description
native AUTO Selects the best strategy for your database
identity IDENTITY Use an identity column (MS SQL, MySQL, HSQL, …)
sequence SEQUENCE Use a sequence (Oracle, PostgreSQL, SAP DB, …)
- TABLE Uses a table to hold last generated values for PKs
hilo - Like table, uses efficient algorithm to generate values
seqhilo - Like regular hilo, but using a sequence
increment - Finds the current max value and increments by 1*
uuid.hex - Creates globally unique 128-bit UUIDs
guid - Uses MySQL and MS SQL server global uid generator
select - Have Hibernate select a value generated by a trigger
assigned (implicit) Specifies that the value is assigned by the application
© 2014 Time2Master 12
Specifying Identity Generation
@GeneratedValue
@Entity @Entity Defaults to
public class Person { Specify the generation strategy public class Person { ‘AUTO’
@Id @Id when not
@GeneratedValue(strategy=GenerationType.AUTO) @GeneratedValue
private long id; private long id;
specified
private String name; private String name;
<generator> tag
<hibernate-mapping>
<class name="identity.Person"> Always have to
<id name="id"> specify a strategy,
<generator class="native" /> cannot leave it off
</id>
<property name="name" />
</class>
</hibernate-mapping>
© 2014 Time2Master 13
Identity Column
Identity columns are columns that can
automatically generate the next unique id
@Entity
public class Person { JPA identity strategy
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String name;
<hibernate-mapping>
<class name="identity.Person">
<id name="id">
<generator class="identity" />
</id>
<property name="name" />
</class>
XML identity strategy
</hibernate-mapping>
If your database support identity columns the
native strategy will default to using them
© 2014 Time2Master 14
Sequence
The SEQUENCE strategy will default to using
the ‘hibernate_sequence’ for all tables
The AUTO strategy will do so too if sequence is the
default strategy (Oracle, PostgreSQL)
@Entity
public class Person { Both AUTO and SEQUENCE
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
private long id;
private String name;
<hibernate-mapping>
<class name="identity.Person">
<id name="id">
<generator class="sequence" />
</id> Both native and sequence
<property name="name" />
</class>
</hibernate-mapping>
© 2014 Time2Master 15
Sequences
By default Hibernate only uses a single
sequence called ‘hibernate-sequence’
You can specify additional custom sequences
Tip: You can use the native strategy and still
also specify a custom sequence
© 2014 Time2Master 16
Using Custom Sequences
Create Custom Sequence
@Entity
@SequenceGenerator(name="personSeq", sequenceName="PERSON_SEQUENCE")
public class Person_annotated_sequence {
@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE, generator="personSeq")
private long id;
Use Custom Sequence
...
<hibernate-mapping>
<class name="identity.Person">
<id name="id" >
Use ‘sequence’ strategy
<generator class="sequence">
<param name="sequence">PERSON_SEQUENCE</param>
</generator>
</id> Specify the custom
<property name="name" /> sequence
</class>
</hibernate-mapping>
© 2014 Time2Master 17
Entity Class Mapping
MAPPING DATA TYPES
© 2014 Time2Master 18
Data Types
So far we haven’t specified any data types
Hibernate automatically mapped to SQL types
You can be very specific
Specify the data type, length, precision and more
@Entity
public class Person { Name will be stored as:
@Id FULLNAME VARCHAR(255) NOT NULL
@GeneratedValue
private long id;
@Column(name="FULLNAME", length=255, nullable=false)
private String name;
...
© 2014 Time2Master 19
Specify Date Type
Sometimes you need to be specific
Should a java.util.Date be stored as date, as a time
or as a timestamp in the database?
@Entity
public class Person {
@Id
@GeneratedValue
private long id;
private String name; Birthday will be
@Temporal(TemporalType.DATE) stored as a Date
private Date birthday;
...
If left unspecified a java.util.Date will be
stored as a timestamp to preserve accuracy
© 2014 Time2Master 20
Annotation Types
Reflection is used to find java type information
Use @Column to specify more details
Use @Temporal to specify how a Date should
be persisted (DATE, TIME or TIMESTAMP)
Use @Lob to indicate Large values
Use @Transient to indicate that a property
should not be persisted
© 2014 Time2Master 21
All in One Example
@Entity
public class Person { Name will be stored as:
@Id FULLNAME VARCHAR(255) NOT NULL
@GeneratedValue
private long id;
@Column(name="FULLNAME", length=255, nullable=false)
private String name;
@Temporal(TemporalType.DATE) Birthday will be
private Date birthday; stored as a Date
@Lob
private String biography;
@Transient
private String temp;
Biography will be stored as CLOB
instead of VARCHAR
...
Temp will not be stored in the database
© 2014 Time2Master 22
Basic Hibernate XML Types
Hibernate Type Java Type SQL Type
byte byte or java.lang.Byte TINYINT
short short or java.lang.Short SMALLINT
integer int or java.lang.Integer INTEGER
long long or java.lang.Long BIGINT
float float or java.lang.Float FLOAT
double double or java.lang.Double DOUBLE
big_decimal java.math.BigDecimal NUMERIC
boolean boolean BIT
yes_no boolean CHAR(1) – ‘Y’ or ‘N’
true_false boolean CHAR(1) – ‘T’ or ‘F’
string java.lang.String VARCHAR
character char, java.lang.Character or CHAR(1)
java.lang.String
© 2014 Time2Master 23
Date Time & Large Values
Hibernate Type Java Type SQL Type
date java.util.Date or java.sql.Date DATE
time java.util.Date or java.sql.Time TIME
timestamp java.util.Date or java.sql.Timestamp TIMESTAMP
calendar java.util.Calendar TIMESTAMP
calendar_date java.util.Calendar DATE
Hibernate Type Java Type SQL Type
binary byte[] or java.lang.Byte[] VARBINARY
text java.lang.String CLOB
clob java.sql.Clob CLOB
blob Java.sql.Blob BLOB
serializable java.io.serializable VARBINARY
© 2014 Time2Master 24
XML Type Example
Same class and properties as the
previous annotation example
public class Person {
private long id; Now without
private String name; annotations
private Date birthday;
private String biography;
private String temp;
...
Name will be stored as:
<hibernate-mapping> FULLNAME VARCHAR(255) NOT NULL
<class name="model.Person" table="MY_PERSON">
<id name="id" type="long" column="PERSON_ID">
<generator class="native" />
</id>
Birthday will be
<property name="name" column="FULLNAME"
type="string" length="255" not-null="true" /> stored as a Date
<property name="birthday" column="BIRTHDAY" type="date" />
<property name="biography" type="text" />
</class>
Biography will be stored as CLOB
</hibernate-mapping>
instead of VARCHAR
Temp is not listed and will not
be stored in the database
© 2014 Time2Master 25
Entity Class Mapping
SPECIFYING ACCESS TYPE
© 2014 Time2Master 26
Property or Field Access
Hibernate can access objects in two ways
property access gets and sets object values
through getter /setter methods
field access gets and sets object values directly
from / to the fields
@Entity @Entity
public class Person { public class Person {
@Id private long id;
@GeneratedValue private String name;
private long id;
private String name; public Person() {}
public Person(String name) { this.name = name; }
...
JPA field access @Id
@GeneratedValue JPA property access
public long getId() { return id; }
private void setId(long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
}
© 2014 Time2Master 27
Specifying Access with Annotations
The JPA specification lets you set the Access Type
with the location of @Id
Placing @Id on a field specifies field access for the
entire object
All other mapping annotations should be on the fields
Placing @Id on a getter specifies property access for
the entire object
All other mapping annotations should be on the getters
Using additional annotations you can also change
access for individual fields
© 2014 Time2Master 28
Access Example
@Entity
public class Person {
private long id;
private String name;
private Date birthday;
All other public Person() {}
annotations public Person(String name) { this.name = name; }
have to be @Id on a getter sets property access for all attributes
on getter @Id
@GeneratedValue
methods as public long getId() { return id; }
well private void setId(long id) { this.id = id; }
@Access(AccessType.FIELD) Name will be accessed
public String getName() { return name; } through the field instead
public void setName(String name) { this.name = name; }
@Temporal(TemporalType.DATE)
public Date getBirthday() { return birthday; }
public void setBirthday(Date birthday) { this.birthday = birthday; }
}
Birthday is still accessed
through getters / setters
© 2014 Time2Master 29
Setting Access with XML
Use the “default-access” attribute on the
<hibernate-mapping> tag to set the default
Use the “access” attribute on the <property>
tag to change access for individual fields
Sets the default access
for Person to field
<hibernate-mapping default-access="field">
<class name="model.Person">
<id name="id">
<generator class="native" />
</id>
<property name="name" access="property" /> Changes the access for the name
<property name="birthday" type="date" /> attribute to property
</class>
</hibernate-mapping>
Birthday will be accessed through
its field (as set by the default)
© 2014 Time2Master 30
Access / Encapsulation
Property access hides implementation details
Maintains OO Principle of Encapsulation
Hibernate dirty checking compares by value
With property access your implementation can
differ from your relational mapping without
disturbing Hibernate
© 2014 Time2Master 31
Encapsulation Example XML
public class Person {
private long id;
Table: PERSON
3 field implementation
private String firstname; details are encapsulated
private String lastname;
Mapped to 2 column table
public Person() {}
public long getId() { return id; } Firstname and lastname are
public void setId(long id) { this.id = id; }
combined in getter
public String getName() { return firstname + " " + lastname; }
public void setName(String name) {
StringTokenizer st = new StringTokenizer(name);
firstname = st.nextToken();
lastname = st.nextToken(); Firstname and lastname are
} separated in setter
public String getFirstname() { return firstname; }
public void setFirstname(String firstname) { this.firstname = firstname; }
public String getLastname() { return lastname; }
public void setLastname(String lastname) { this.lastname = lastname; }
}
<hibernate-mapping default-access="property">
<class name="model.Person" >
<id name="id"> Property access
<generator class="native"/>
</id>
<property name="name" /> maps the 2 fields:
</class> id and name
</hibernate-mapping>© 2014 Time2Master 32
Annotations Encapsulation Example
@Entity
public class Person { Table: PERSON
private long id;
private String firstname; Three class properties get
private String lastname; mapped to two columns
public Person() {}
@Id Property access
@GeneratedValue
public long getId() { return id; }
public void setId(long id) { this.id = id; }
@Column
public String getName() { return firstname + " " + lastname; }
public void setName(String name) { /* see code prev slide */; }
@Transient firstname
@Transient and lastname
public String getFirstname() { return firstname; }
public void setFirstname(String firstname) { this.firstname = firstname; }
@Transient
public String getLastname() { return lastname; }
public void setLastname(String lastname) { this.lastname = lastname; }
}
© 2014 Time2Master 33
Entity Class Mapping
WRAPPING UP
© 2014 Time2Master 34
Mapping Tips
You can specify a package attribute on the
<hibernate-mapping> XML element
No longer need fully qualified class names
Useful when mapping associations
Class name Order Pacakge specified for this mapping
instead of tips.Order
<hibernate-mapping package="cs544">
<class name="Order" table="`order`">
<id name="id" column="`id`"/>
<many-to-one name="customer" class="Person" />
</class>
</hibernate-mapping>
Person instead of cs544.Person
© 2014 Time2Master 35
Active Learning
What do the following annotations do:
@Temporal @Transient
How does property access work, how does
field access work?
© 2014 Time2Master 36
Module Summary
In this module we covered entity class
mapping including:
Mapping an entity classes to tables
Mapping properties to columns
Mapping Identity and setting Identity Generation
Mapping Data types
Property / Field Access
These are the tools you use to map any class
© 2014 Time2Master 37