Enterprise Java Persistence Core ObjectRelational Mapping v 130501
Enterprise Java Persistence: Core Object/Relational Mapping v 130501 Java Persistence: Core ORM 1
Goals Enterprise Java • Be able to map a single class and properties to the database using class annotations and ORM descriptors • Be able to get and set properties using get/set API calls instead of SQL v 130501 Java Persistence: Core ORM 2
Objectives Enterprise Java • Entities – class annotations – orm. xml descriptor • Primary Key Generation • Primary Keys – simple – composite • Fine Tuning Objects • Multi-table Mappings – Secondary Tables – Embedded Objects v 130501 Java Persistence: Core ORM 3
Entities Enterprise Java • Plain Old Java Object (POJO) Classes • Instantiated and used just like any other POJO Bike bike = new Bike(1); bike. set. Make("trek"); bike. set. Model("2200"); bike. set. Size(26); • Mapped to the database schema • Interact with Entity. Manager to perform persistence operations em. persist(bike); Bike bike 2 = em. find(Bike. class, 1); em. remove(bike 2); • Must – have a no-arg constructor (spec says non-private; hibernate can work with private) – be denoted as an Entity (either within class or descriptor) – have at least 1 field/property labeled as Id v 130501 Java Persistence: Core ORM 4
Annotated Entity Example: Bike. java Enterprise Java package ejava. examples. orm. core. annotated; import javax. persistence. *; //brings in JPA Annotations @Entity //tells ORM that this class can be mapped public class Bike { private long id; private String make; private String model; private int size; public Bike() {} public Bike(long id) { this. id = id; } . . . } @Id //tells ORM that this property provides pk simple value public long get. Id() { return id; } @Suppress. Warnings("unused") //ORM will use this to set pk value private void set. Id(long id) { this. id = id; } public String get. Make() { return make; } public void set. Make(String make) { this. make = make; } v 130501 Java Persistence: Core ORM 5
Enterprise Java Non-Annotated Entity Example: Bike. java package ejava. examples. orm. core. mapped; public class Bike { private long id; private String make; private String model; private int size; public Bike() {} public Bike(long id) { this. id = id; } . . . } //orm. xml file will map this field to Identity public long get. Id() { return id; } @Suppress. Warnings("unused") //ORM will use this to set pk value private void set. Id(long id) { this. id = id; } public String get. Make() { return make; } public void set. Make(String make) { this. make = make; } v 130501 Java Persistence: Core ORM 6
Entity Example: META-INF/persistence. xml Enterprise Java <? xml version="1. 0" encoding="UTF-8"? > <persistence xmlns="http: //java. sun. com/xml/ns/persistence" xmlns: xsi="http: //www. w 3. org/2001/XMLSchema-instance" xsi: schema. Location="http: //java. sun. com/xml/ns/persistence_1_0. xsd" version="1. 0"> <persistence-unit name="orm. Core"> <!-- These could have been rolled into a single file. META-INF/orm. xml is the default location for a single file approach. --> <mapping-file>orm/Bike-orm. xml</mapping-file> <mapping-file>orm/Car-orm. xml</mapping-file>. . . <properties> <property name="hibernate. hbm 2 ddl. auto" value="create"/>. . . </properties> </persistence-unit> </persistence> v 130501 Java Persistence: Core ORM 7
Enterprise Java Non-Annotated Entity Example: Bike-orm. xml <? xml version="1. 0" encoding="UTF-8"? > <entity-mappings xmlns="http: //java. sun. com/xml/ns/persistence/orm" xmlns: xsi="http: //www. w 3. org/2001/XMLSchema-instance" xsi: schema. Location="http: //java. sun. com/xml/ns/persistence/orm_1_0. xsd" version="1. 0"> <entity class="ejava. examples. orm. core. mapped. Bike" access="PROPERTY" metadata-complete="true" name="Mapped. Bike"> <!-- name used to avoid name collision with annotated Bike example --> <table name="Bike"/> <attributes> <id name="id"/> </attributes> </entity-mappings> v 130501 Java Persistence: Core ORM 8
Example Directory Layout Enterprise Java target/classes/ |-- META-INF | `-- persistence. xml |-- ejava | `-- examples | `-- orm | `-- core | |-- annotated | | |-- Bike. class | `-- mapped | |-- Bike. class `-- orm |-- Bike-orm. xml v 130501 Java Persistence: Core ORM 9
Entity Name Enterprise Java • Defaults to unqualified name of entity class • Used to determine default table name – Bike class -> Bike table – SQL from Hypersonic log. . . create table Bike (id bigint not null, make varchar(255), size integer not null, model varchar(255), primary key (id)) • Used to refer to class in EJB-QL • Can be assigned using optional name property – @Entity(name=”entity_name”) • Table name can be specified separate from entity name – @Table(name=”table_name”) v 130501 Java Persistence: Core ORM 10
Field/Property Access using @Id Enterprise Java • Labels fields/properties used for primary key • Determines access type for remaining values – field – direct access to fields within class @Entity public class Bike { @Id private long id; – property – access through getter/setter methods @Entity public class Bike { private long id; . . . @Id //annotation must be on getter method; not setter public long get. Id() { return id; } private void set. Id(long id) { this. id = id; } v 130501 Java Persistence: Core ORM 11
Field/Property Access using orm. xml Enterprise Java • FIELD <entity class="ejava. examples. orm. core. mapped. Bike" access="FIELD" metadata-complete="true" name="Mapped. Bike"> <table name="Bike"/> <attributes> <id name="id"/> </attributes> </entity> • PROPERTY <entity class="ejava. examples. orm. core. mapped. Bike" access="PROPERTY" metadata-complete="true" name="Mapped. Bike"> <table name="Bike"/> <attributes> <id name="id"/> </attributes> </entity> v 130501 Java Persistence: Core ORM 12
Getting Started Enterprise Java • Java First – appropriate for quick prototypes – most vendors provide tools to create database schema from Java classes • database schema maps closely to Java classes and has not been optimized – less use of javax. persistence metadata because defaults sufficient for functionality of prototype • Database Schema First – common in legacy environments and large developments – vendors provide tools to create Java classes from database schema • Java classes map closely to database schema and do not necessarily represent the business or uses of the application – more use of javax. persistence metadata required to use proper business classes with existing schema v 130501 Java Persistence: Core ORM 13
Elementary Schema Mappings Enterprise Java • Core Mappings – @Table. name – assigns table name – @Column. name – assigns column name • More detailed attributes – only necessary when generating schema – @Column • • • v 130501 unique – column will be defined as being unique nullable – column will be defined as being nullable insertable – column will be included in inserts updatable – column will be included in updates table – maps column to table separate from class length – length of VARCHAR() when using a String precision – defines # digits in NUMERIC types scale – defines # digits to right of decimal in NUMERIC types column. Definition – exact DDL to use for schema Java Persistence: Core ORM 14
Enterprise Java Example Database Schema for Mapping create table ORMCORE_CAR ( CAR_ID bigint not null, CAR_YEAR integer not null, CAR_MODEL varchar(20) not null, CAR_MAKE varchar(20) not null, CAR_COST double, primary key (CAR_ID) ) v 130501 Java Persistence: Core ORM 15
Database Mappings using Annotations Enterprise Java package ejava. examples. orm. core. annotated; import javax. persistence. *; @Entity @Table(name="ORMCORE_CAR", schema="PUBLIC") public class Car { private long id; private String make; private String model; private int year; private Big. Integer cost; public Car() {} public Car(long id) { this. id = id; } @Id @Column(name="CAR_ID", nullable=false) public long get. Id() { return id; } @Suppress. Warnings("unused") private void set. Id(long id) { this. id = id; } v 130501 Java Persistence: Core ORM 16
Database Mappings using Annotations (cont. ) Enterprise Java @Column(name="CAR_MAKE", unique=false, nullable=false, insertable=true, updatable=true, table="", //note: we can point to another table to get prop length=20) public String get. Make() { return make; } public void set. Make(String make) { this. make = make; } @Column(name="CAR_MODEL", nullable=false, length=20) public String get. Model() { return model; } public void set. Model(String model) { this. model = model; } v 130501 Java Persistence: Core ORM 17
Database Mappings using Annotations (cont. ) Enterprise Java @Column(name="CAR_YEAR", nullable=false) public int get. Year() { return year; } public void set. Year(int year) { this. year = year; } @Column(name="CAR_COST", precision=7, scale=2) public Big. Decimal get. Cost() { return cost; } public void set. Cost(Big. Decimal cost) { this. cost = cost; }. . . } v 130501 Java Persistence: Core ORM 18
Database Mappings using Descriptor Enterprise Java <entity-mappings> <entity class="ejava. examples. orm. core. mapped. Car" access="PROPERTY" metadata-complete="true" name="Mapped. Car"> <table name="ORMCORE_CAR"/> <attributes> <id name="id"> <column name="CAR_ID" nullable="false"/> </id> <basic name="make"> <column name="CAR_MAKE" nullable="false" insertable="true" updatable="true" table="" length="20"/> </basic> <basic name="model"> <column name="CAR_MODEL" nullable="false" length="20"/> </basic>. . . v 130501 Java Persistence: Core ORM 19
Database Mappings using Descriptor (cont. ) Enterprise Java . . . <basic name="year"> <column name="CAR_YEAR" nullable="false"/> </basic> <basic name="cost"> <column name="CAR_COST" precision="7" scale="2"/> </basic> </attributes> </entity-mappings> v 130501 Java Persistence: Core ORM 20
More on Scale Enterprise Java //precision defined in ORM as precision=7, scale=2 car. set. Cost(new Big. Decimal("12345. 66")); em. persist(car); em. flush(); em. clear(); //get a fresh copy from the DB Car car 2 = em. find(Car. class, car. get. Id()); assert. True("unexpectected value", car. get. Cost(). equals(car 2. get. Cost())); //update beyond scale values -- too many digits to right of decimal car 2. set. Cost(new Big. Decimal("1234. 666")); em. flush(); em. clear(); Car car 3 = em. find(Car. class, car. get. Id()); log. info("car 2. cost=" + car 2. get. Cost()); log. info("car 3. cost=" + car 3. get. Cost()); assert. False("unexpected scale", car 2. get. Cost(). equals(car 3. get. Cost())); //output -car 2. cost=1234. 666 -car 3. cost=1234. 67 v 130501 Java Persistence: Core ORM 21
More on Precision Enterprise Java //update beyond precision values -- too many digits overall car 2 = car 3; car 2. set. Cost(new Big. Decimal("123456. 66")); try { em. flush(); fail("database accepted too many digits"); } catch (Persistence. Exception ex) { log. info("caught expected exception: " + ex); } //output -caught expected exception: javax. persistence. Persistence. Exception: org. hibernate. exception. Data. Exception: Value too long for column "CAR_COST DECIMAL(7, 2)": "123456. 66 (8)"; SQL statement: update ORMCORE_CAR set CAR_COST=? , CAR_MAKE=? , CAR_MODEL=? , CAR_YEAR=? where CAR_ID=? [22001 -168] v 130501 Java Persistence: Core ORM 22
Primary Keys Enterprise Java • Every entity must have an primary key • Primary keys must be unique • Map to one (simple primary key) or more (composite primary key) properties • Properties must be of type – Java primitive types (including wrappers; Integer, etc. ) – java. lang. String – primary key class (composed of legal property types) v 130501 Java Persistence: Core ORM 23
Enterprise Java Generated Primary Keys v 130501 Java Persistence: Core ORM 24
Generated Primary Keys Enterprise Java public interface javax. persistence. Generated. Value { javax. persistence. Generation. Type strategy(); String generator(); } public final class javax. persistence. Generation. Type extends java. lang. Enum{ public static final Generation. Type TABLE; public static final Generation. Type SEQUENCE; public static final Generation. Type IDENTITY; public static final Generation. Type AUTO; . . . } v 130501 Java Persistence: Core ORM 25
AUTO Generation. Type Enterprise Java • Persistence providers required to provide primary key generation • Specific type of generator provided through strategy property – Using annotations @Entity @Table(name="ORMCORE_DRILL") public class Drill implements Serializable {. . . @Id @Generated. Value( //AUTO is default; could be left off strategy=Generation. Type. AUTO) public long get. Id() { return id; } – Using descriptor <entity class="ejava. examples. orm. core. mapped. Drill". . . > <table name="ORMCORE_DRILL"/> <attributes> <id name="id"> <generated-value strategy="AUTO"/> </id> </attributes> </entity> v 130501 Java Persistence: Core ORM 26
AUTO Generation. Type Enterprise Java @Entity @Table(name="ORMCORE_DRILL") public class Drill implements Serializable { private static final long serial. Version. UID = 1 L; private long id=0; private String make; public Drill() {} public Drill(long id) { this. id = id; } @Id @Generated. Value( //AUTO is default strategy=Generation. Type. AUTO) public long get. Id() { return id; } v 130501 Java Persistence: Core ORM 27
AUTO Generated. Value Test (Good) Enterprise Java public void test. AUTOGood() { //note that since PKs are generated, we must pass in //object that has not yet been assigned a PK value. ejava. examples. orm. core. annotated. Drill drill = new Drill(0); drill. set. Make("acme"); //insert a row in the database em. persist(drill); log. info("created drill: " + drill); assert. False(drill. get. Id() == 0 L); } insert into ORMCORE_DRILL (id, make) values (null, ? ) Hibernate: call identity() -created drill: ejava. examples. orm. core. annotated. Drill@1 d 9 e 279, id=1, make=acme v 130501 Java Persistence: Core ORM 28
AUTO Generated. Value Test (Bad) Enterprise Java public void test. AUTOBad() { ejava. examples. orm. core. annotated. Drill drill = new Drill(25 L); drill. set. Make("BD"); boolean exception. Thrown = false; try { assert. False(drill. get. Id() == 0 L); em. persist(drill); } catch (Persistence. Exception ex) { log. info("got expected exception: " + ex); exception. Thrown = true; } assert. True(exception. Thrown); } -got expected exception: javax. persistence. Persistence. Exception: org. hibernate. Persistent. Object. Exception: detached entity passed to persist: ejava. examples. orm. core. annotated. Drill v 130501 Java Persistence: Core ORM 29
TABLE Generation. Type Enterprise Java • Defines user-defined relational table to generate numeric values – example table create table ORMCORE_EB_UID ( UID_ID varchar(255), //holds name of table UID_VAL integer //holds the counter value ) – example values • UID_ID=ORMCORE_EGGBEATER • UID_VAL=2 • Must be setup by a definition of the table generator v 130501 Java Persistence: Core ORM 30
Defining Table Generator • Using annotations • Using descriptor Enterprise Java @Entity @Table(name="ORMCORE_EGGBEATER") @Table. Generator( //note: all but name are optional if gen schema name="eggbeater. Generator", //logical name of gen table="ORMCORE_EB_UID", //name of table with seq pk. Column. Name="UID_ID", //pk column for seq table pk. Column. Value="ORMCORE_EGGBEATER", //pk value in pk col value. Column. Name="UID_VAL", //column for seq value allocation. Size=17 //amount to increment ) public class Egg. Beater implements Serializable { <entity class="ejava. examples. orm. core. mapped. Egg. Beater". . . > <table name="ORMCORE_EGGBEATER"/> <table-generator name="eggbeater. Generator" table="ORMCORE_EB_UID" pk-column-name="UID_ID" pk-column-value="ORMCORE_EGGBEATER" value-column-name="UID_VAL" allocation-size="17"/> v 130501 Java Persistence: Core ORM 31
Using TABLE Generation. Type • • Enterprise Java Using annotations @Id @Generated. Value( strategy=Generation. Type. TABLE, generator="eggbeater. Generator") public long get. Id() { return id; } //use DB table //point to logical def Using descriptor <attributes> <id name="id"> <generated-value strategy="TABLE" generator="eggbeater. Generator"/> </id> </attributes> </entity> v 130501 Java Persistence: Core ORM 32
Testing TABLE Generated. Type Enterprise Java public void test. TABLE() { ejava. examples. orm. core. annotated. Egg. Beater eggbeater = new Egg. Beater(0); eggbeater. set. Make("done right"); //insert a row in the database em. persist(eggbeater); log. info("created eggbeater: " + eggbeater); assert. False(eggbeater. get. Id() == 0 L); } -created eggbeater: ejava. examples. orm. core. annotated. Egg. Beater@1 cba 87, id=1, make=done right v 130501 Java Persistence: Core ORM 33
Finishing the allocation. Size Hibernate: insert into ORMCORE_EGGBEATER (make, id) values (? , ? ) -table id after[2]=1 Hibernate: insert into ORMCORE_EGGBEATER (make, id) values (? , ? ) -table id after[3]=1 … v 130501 Enterprise Java … Hibernate: insert into ORMCORE_EGGBEATER (make, id) values (? , ? ) -table id after[16]=1 Hibernate: insert into ORMCORE_EGGBEATER (make, id) values (? , ? ) -table id after[17]=2 Java Persistence: Core ORM 34
SEQUENCE Generation. Type Enterprise Java • Some DBMS vendors provide – built-in structure to efficiently generate unique IDs v 130501 Java Persistence: Core ORM 35
Defining Sequence Generator Enterprise Java • Using Annotations @Entity @Table(name="ORMCORE_FAN") @Sequence. Generator( name="fan. Sequence", //required logical name sequence. Name="FAN_SEQ", //name in database initial. Value=44, //doesn’t seem to be used allocation. Size=13) //increment seq when reached public class Fan implements Serializable {. . . • Using Descriptor <entity class="ejava. examples. orm. core. mapped. Fan". . . > <table name="ORMCORE_FAN"/> <sequence-generator name="fan. Sequence" sequence-name="FAN_SEQ" initial-value="44" allocation-size="13"/> v 130501 Java Persistence: Core ORM 36
Using SEQUENCE Generation. Type Enterprise Java • Using Annotations @Id @Generated. Value( strategy=Generation. Type. SEQUENCE, generator="fan. Sequence") public long get. Id() { return id; } private void set. Id(long id) { this. id = id; } //point to logical def • Using Descriptor <attributes> <id name="id"> <generated-value strategy="SEQUENCE" generator="fan. Sequence"/> </id> </attributes> v 130501 Java Persistence: Core ORM 37
Testing Sequence Generator Enterprise Java public void test. SEQUENCE() { ejava. examples. orm. core. annotated. Fan fan = new Fan(0); fan. set. Make("cool runner 1"); //insert a row in the database em. persist(fan); log. info("created fan: " + fan); assert. False(fan. get. Id() == 0 L); } -created fan: ejava. examples. orm. core. annotated. Fan@1 dcb 3 cd, id=1, make=cool runner 1 v 130501 Java Persistence: Core ORM 38
IDENITY Generation. Type Enterprise Java • Let database generate – from Hypersonic Log create table ORMCORE_GADGET ( id bigint generated by default as identity (start with 1), make varchar(255), primary key (id) ). . . INSERT INTO ORMCORE_GADGET VALUES(null, 'gizmo 1') INSERT INTO ORMCORE_GADGET VALUES(null, 'gizmo 2') – HSQL supports a “call identity()” stored procedure to get last generated ID v 130501 Java Persistence: Core ORM 39
Using IDENTITY Generator Enterprise Java • Using Annotations @Id @Generated. Value(strategy=Generation. Type. IDENTITY) public long get. Id() { return id; } • Using Descriptor <attributes> <id name="id"> <generated-value strategy="IDENTITY"/> </id> </attributes> v 130501 Java Persistence: Core ORM 40
Testing Identity Generator Enterprise Java public void test. IDENTITY() { ejava. examples. orm. core. annotated. Gadget gadget = new Gadget(0); gadget. set. Make("gizmo 1"); //insert a row in the database em. persist(gadget); log. info("created gadget: " + gadget); assert. False(gadget. Id() == 0 L); } -created gadget: ejava. examples. orm. core. annotated. Gadget@23 d 278, id=1, make=gizmo 1 v 130501 Java Persistence: Core ORM 41
Enterprise Java Composite Primary Keys v 130501 Java Persistence: Core ORM 42
Composite Primary Keys Enterprise Java • Primary Key consisting of multiple properties • Can be represented by a primary key class – must be Serializable public class Mower. PK implements java. io. Serializable { – must have a public no-arg constructor public Mower. PK() {} – must implement equals() and hash. Code() methods public int hash. Code() {. . . } public boolean equals(Object obj) {. . . } v 130501 Java Persistence: Core ORM 43
Example Composite PK Class Enterprise Java package ejava. examples. orm. core; import java. io. Serializable; public class Mower. PK implements Serializable { private static final long serial. Version. UID = 1 L; private String make; private String model; public Mower. PK() {} public Mower. PK(String make, String model) { this. make = make; this. model = model; } public static long get. Serial. Version. UID() { return serial. Version. UID; } public String get. Make() { return make; } private void set. Make(String make) { this. make = make; } v 130501 Java Persistence: Core ORM 44
Example Composite PK Class (cont. ) Enterprise Java public String get. Model() { return model; } private void set. Model(String model) { this. model = model; } public int hash. Code() { return make. hash. Code() + model. hash. Code(); } public boolean equals(Object obj) { try { if (this == obj) return true; return make. equals(((Mower. PK)obj). get. Make()) && model. equals(((Mower. PK)obj). get. Model()); } catch (Throwable ignored) { //catch NP & Cast Exceptions return false; } } public String to. String() { return super. to. String() + ", make=" + make + ", model=" + model; v 130501 Java Persistence: Core ORM } } 45
Using a Primary Key Class as an Id. Class Enterprise Java • Not used internally by persistent class • Used by entity manager • Properties of Id. Class map to @Id properties of persistent class • Example Database Schema create table ORMCORE_MOWER ( make varchar(255) not null, model varchar(255) not null, size integer not null, primary key (make, model) ) v 130501 Java Persistence: Core ORM 46
Example Usage of an Id. Class Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; import ejava. examples. orm. core. Mower. PK; @Entity @Table(name="ORMCORE_MOWER") @Id. Class(Mower. PK. class) public class Mower implements Serializable { private static final long serial. Version. UID = 1 L; private String make; private String model; private int size; public Mower() {} public Mower(String make, String model) { this. make = make; this. model = model; } v 130501 Java Persistence: Core ORM 47
Example Usage of an Id. Class (cont. ) Enterprise Java @Id @Column(nullable=false, updatable=false) public String get. Make() { return make; } private void set. Make(String make) { this. make = make; } @Id @Column(nullable=false, updatable=false) public String get. Model() { return model; } private void set. Model(String model) { this. model = model; } public int get. Size() { return size; } public void set. Size(int size) { this. size = size; } v 130501 Java Persistence: Core ORM 48
Example Usage of an Id. Class Enterprise Java • Using a Descriptor <entity class="ejava. examples. orm. core. mapped. Mower" access="PROPERTY" metadata-complete="true" name="Mapped. Mower"> <table name="ORMCORE_MOWER"/> <id-class="ejava. examples. orm. core. Mower. PK"/> <attributes> <id name="make"/> <id name="model"/> </attributes> </entity> v 130501 Java Persistence: Core ORM 49
Example Usage of an Id. Class Enterprise Java public void test. Id. Class() { ejava. examples. orm. core. annotated. Mower mower = new Mower("acme", "power devil 2"); mower. set. Size(21); //insert a row in the database em. persist(mower); log. info("created mower: " + mower); -created mower: ejava. examples. orm. core. annotated. Mower@d 2 b 64 e, make=acme, model=power devil 2, size=21 Mower mower 2 = em. find(Mower. class, new Mower. PK("acme", "power devil 2")); assert. Not. Null(mower 2); log. info("found mower: " + mower 2); assert. Equals(mower. get. Size(), mower 2. get. Size()); -found mower: ejava. examples. orm. core. annotated. Mower@d 2 b 64 e, make=acme, model=power devil 2, size=21 v 130501 Java Persistence: Core ORM 50
Using a Primary Key Class as an Embedded. Id Enterprise Java • Embedded directly into persisted class • Mapping fields – way 1: embed column mappings in Embedded. Id class @Column(name="NAPSACK_MAKE") public String get. Make() { return make; } public void set. Make(String make) { this. make = make; } – way 2: provider Attribute. Overrides in persisted class @Embedded. Id @Attribute. Overrides({ @Attribute. Override(name="make", column=@Column(name="PEN_MAKE")), @Attribute. Override(name="model", column=@Column(name="PEN_MODEL")) }) v 130501 Java Persistence: Core ORM 51
Example Embedded. Id Enterprise Java • Database Schema create table ORMCORE_NAPSACK ( NAPSACK_MAKE varchar(255) not null, NAPSACK_MODEL varchar(255) not null, size integer not null, primary key (NAPSACK_MAKE, NAPSACK_MODEL) ) v 130501 Java Persistence: Core ORM 52
Example Embedded. Id Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; @Embeddable public class Napsack. PK implements Serializable { private static final long serial. Version. UID = 1 L; private String make; private String model; public Napsack. PK() {} public Napsack. PK(String make, String model) { this. make = make; this. model = model; } v 130501 Java Persistence: Core ORM 53
Example Embedded. Id (cont. ) Enterprise Java @Column(name="NAPSACK_MAKE") //maps field to col of containing class public String get. Make() { return make; } public void set. Make(String make) { this. make = make; } @Column(name="NAPSACK_MODEL")//maps field to col of containing class public String get. Model() { return model; } public void set. Model(String model) { this. model = model; } v 130501 Java Persistence: Core ORM 54
Example Embedded. Id (cont. ) Enterprise Java public int hash. Code() { return make. hash. Code() + model. hash. Code(); } public boolean equals(Object obj) { try { if (this == obj) return true; return make. equals(((Napsack. PK)obj). get. Make()) && model. equals(((Napsack. PK)obj). get. Model()); } catch (Throwable ignored) { //catch NP & Cast Exceptions return false; } } public String to. String() { return super. to. String() + ", make=" + make + ", model=" + model; } } v 130501 Java Persistence: Core ORM 55
Example Usage of Embedded. Id using Annotations Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; @Entity @Table(name="ORMCORE_NAPSACK") public class Napsack implements Serializable { private static final long serial. Version. UID = 1 L; private Napsack. PK pk; private int size; public Napsack() {} public Napsack(String make, String model) { this. pk = new Napsack. PK(make, model); } @Embedded. Id public Napsack. PK get. Pk() { return pk; } public void set. Pk(Napsack. PK pk) { this. pk = pk; } v 130501 Java Persistence: Core ORM 56
Example Usage of Embedded. Id using orm. xml Enterprise Java <entity-mappings> <entity class="ejava. examples. orm. core. mapped. Napsack" access="PROPERTY" metadata-complete="true" name="Mapped. Napsack"> <table name="ORMCORE_NAPSACK"/> <attributes> <embedded-id name="pk"/> </attributes> </entity> <embeddable class="ejava. examples. orm. core. mapped. Napsack. PK"> <attributes> <basic name="make"> <column name="NAPSACK_MAKE"/> </basic> <basic name="model"> <column name="NAPSACK_MODEL"/> </basic> </attributes> </embeddable> </entity-mappings> v 130501 Java Persistence: Core ORM 57
Example Embedded. Id to be Overridden Enterprise Java • Supply or override database mapping of PK class in embedded class • Example PK Class @Embeddable public class Make. Model. PK implements Serializable { private String make; private String model; • Example Database Schema create table ORMCORE_PEN ( PEN_MAKE varchar(255) not null, PEN_MODEL varchar(255) not null, size integer not null, primary key (PEN_MAKE, PEN_MODEL) ) v 130501 Java Persistence: Core ORM 58
Supply/Override Mappings of Embedded. Id in Persisted Class Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; @Entity @Table(name="ORMCORE_PEN") public class Pen implements Serializable { private static final long serial. Version. UID = 1 L; private Make. Model. PK pk; private int size; public Pen() {} public Pen(String make, String model) { this. pk = new Make. Model. PK(make, model); } @Embedded. Id @Attribute. Overrides({ @Attribute. Override(name="make", column=@Column(name="PEN_MAKE")), @Attribute. Override(name="model", column=@Column(name="PEN_MODEL")) }) public Make. Model. PK get. Pk() { return pk; } public void set. Pk(Make. Model. PK pk) { this. pk = pk; } v 130501 Java Persistence: Core ORM 59
Supply/Override Mappings of Embedded. Id using orm. xml <entity-mappings> <entity class="ejava. examples. orm. core. mapped. Pen" access="PROPERTY" metadata-complete="true" name="Mapped. Pen"> <table name="ORMCORE_PEN"/> <attributes> <embedded-id name="pk"> <attribute-override name="make"> <column name="PEN_MAKE"/> </attribute-override> <attribute-override name="model"> <column name="PEN_MODEL"/> </attribute-override> </embedded-id> </attributes> </entity> <embeddable class="ejava. examples. orm. core. mapped. Make. Model. PK"> <attributes> <basic name="make"/> <basic name="model"/> </attributes> </embeddable> v 130501 Java Persistence: Core ORM </entity-mappings> Enterprise Java 60
Using Overridden Embedded. Id Example Enterprise Java public void test. Embedded. Id. Overrides() { ejava. examples. orm. core. annotated. Pen pen = new Pen("acme", "quick write 2"); pen. set. Size(3); //insert a row in the database em. persist(pen); log. info("created pen: " + pen); -created pen: ejava. examples. orm. core. annotated. Pen@1 f 52460, pk=ejava. examples. orm. core. annotated. Make. Model. PK@d 4216 b 00, make=acme, model=quick write 2, size=3 Pen pen 2 = em. find( Pen. class, new Make. Model. PK("acme", "quick write 2")); assert. Not. Null(pen 2); log. info("found pen: " + pen 2); assert. Equals(pen. get. Size(), pen 2. get. Size()); -found pen: ejava. examples. orm. core. annotated. Pen@1 f 52460, pk=ejava. examples. orm. core. annotated. Make. Model. PK@d 4216 b 00, make=acme, model=quick write 2, size=3 v 130501 Java Persistence: Core ORM 61
Enterprise Java Property Mappings v 130501 Java Persistence: Core ORM 62
Fine Tunings Enterprise Java • Transient – tell persistence provider to ignore this property • Fetch. Type – hint to persistence provider whether eager or lazy load of property would be appropriate for intended use of object • Temporal – specifying guidance for mapping Date and Calendar properties • Lob – mapping BLOB and CLOB types • Enumerated – mapping Java SE 5 Enumerated types v 130501 Java Persistence: Core ORM 63
Using Transient Enterprise Java • Database Schema create table ORMCORE_TANK ( id bigint not null, make varchar(255), model varchar(255), primary key (id) ) • Using Descriptor <entity class="ejava. examples. orm. core. mapped. Tank" access="PROPERTY" metadata-complete="true" name="Mapped. Tank"> <table name="ORMCORE_TANK"/> <attributes> <id name="id"/> <transient name="make. Model"/> </attributes> </entity> v 130501 Java Persistence: Core ORM 64
Using Annotations and Transient Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; @Entity @Table(name="ORMCORE_TANK") public class Tank implements Serializable { private static final long serial. Version. UID = 1 L; private long id; private String make; private String model; public Tank() {} public Tank(long id) { this. id = id; } @Id public long get. Id() { return id; } private void set. Id(long id) { this. id = id; } @Transient public String get. Make. Model() { return make + " " + model; } //not there is no set. Make. Model(String). . . v 130501 Java Persistence: Core ORM 65
Testing Transient Enterprise Java public void test. Transient() { log. info("test. Transient"); ejava. examples. orm. core. annotated. Tank tank = new Tank(1); tank. set. Make("acme"); tank. set. Model("great guns"); } //insert a row in the database em. persist(tank); log. info("created tank: " + tank); -created tank: ejava. examples. orm. core. annotated. Tank@6 a 2 f 81, make=acme, model=great guns v 130501 Java Persistence: Core ORM 66
Lob Example Enterprise Java • String stored as CLOB • Further labeled as Fetch. Type. LAZY to hint it won't be used • Database Schema – from Hypersonic Log create table ORMCORE_UMBRELLA ( id bigint not null, make longvarchar, model varchar(255), primary key (id) ) v 130501 Java Persistence: Core ORM 67
Lob Example Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; @Entity @Table(name="ORMCORE_UMBRELLA") public class Umbrella implements Serializable { private static final long serial. Version. UID = 1 L; private long id; private String make; private String model; public Umbrella() { } public Umbrella(long id) { this. id = id; } @Id public long get. Id() private void set. Id(long id) { return id; } { this. id = id; } @Lob @Basic(fetch=Fetch. Type. LAZY) public char[] get. Make() { return make. to. Char. Array(); } public void set. Make(char[] make) { this. make = new String(make); } v 130501 Java Persistence: Core ORM 68
Temporal and Enum Types Enterprise Java • Temporal – Date – Timestamp • Enum – ordinal value – name value • Example Schema create table ORMCORE_VASE ( id bigint not null, ADate date, ATime time, ATimestamp timestamp, color. Id integer, color. Name varchar(255), primary key (id)) v 130501 Java Persistence: Core ORM 69
Example with Temporal and Enum Types Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; java. util. Date; javax. persistence. *; ejava. examples. orm. core. Color. Type; @Entity @Table(name="ORMCORE_VASE") public class Vase implements Serializable { private static final long serial. Version. UID = 1 L; private long id; private Date a. Date; private Date a. Timestamp; private Color. Type color. Id; private Color. Type color. Name; public Vase() {} public Vase(long id) { this. id = id; } v 130501 Java Persistence: Core ORM 70
Using Temporal Metadata Enterprise Java @Temporal(Temporal. Type. DATE) public Date get. ADate() { return a. Date; } public void set. ADate(Date date) { a. Date = date; } @Temporal(Temporal. Type. TIME) public Date get. ATime() { return a. Time; } public void set. ATime(Date time) { a. Time = time; } @Temporal(Temporal. Type. TIMESTAMP) public Date get. ATimestamp() { return a. Timestamp; } public void set. ATimestamp(Date timestamp) { a. Timestamp = timestamp; } v 130501 Java Persistence: Core ORM 71
Using Enum Metadata Enterprise Java @Enumerated(Enum. Type. ORDINAL) public Color. Type get. Color. Id() { return color. Id; } public void set. Color. Id(Color. Type color. Id) { this. color. Id = color. Id; } @Enumerated(Enum. Type. STRING) public Color. Type get. Color. Name() { return color. Name; } public void set. Color. Name(Color. Type color. Name) { this. color. Name = color. Name; } @Id public long get. Id() { return id; } private void set. Id(long id) { this. id = id; } v 130501 Java Persistence: Core ORM 72
Enterprise Java Defining Temporal and Enum Types in orm. xml <entity class="ejava. examples. orm. core. mapped. Vase" access="PROPERTY" metadata-complete="true" name="Mapped. Vase"> <table name="ORMCORE_VASE"/> <attributes> <id name="id"/> <basic name="a. Date"> <temporal>DATE</temporal> </basic> <basic name="a. Time"> <temporal>TIME</temporal> </basic> <basic name="a. Timestamp"> <temporal>TIMESTAMP</temporal> </basic> <basic name="color. Id"> <enumerated>ORDINAL</enumerated> </basic> <basic name="color. Name"> <enumerated>STRING</enumerated> </basic> </attributes> </entity-mappings> v 130501 Java Persistence: Core ORM 73
Testing Temporal and Enum Values Enterprise Java public void test. Values() { log. info("test. Dates"); ejava. examples. orm. core. annotated. Vase vase = new Vase(1); Date date = new Date(); vase. set. ADate(date); vase. set. ATimestamp(date); vase. set. Color. Id(Color. Type. RED); vase. set. Color. Name(Color. Type. RED); //insert a row in the database em. persist(vase); log. info("created case: " + vase); -created case: ejava. examples. orm. core. annotated. Vase@1486306, id=1, a. Date=Sat Sep 23 14: 08: 22 EDT 2006, a. Timestamp=Sat Sep 23 14: 08: 22 EDT 2006, color. Id=RED, color. Name=RED select * from ID ADATE -- -----1 2006 -09 -23 v 130501 ORMCORE_VASE ATIMESTAMP COLORID COLORNAME -------------------14: 08: 22 2006 -09 -23 14: 08: 22. 221000000 0 RED Java Persistence: Core ORM 74
Enterprise Java Multiple Table Mappings v 130501 Java Persistence: Core ORM 75
Multi-Table Mapping Example Enterprise Java • Watch has a Maker and Owner • Example Database Schema create table ORMCORE_OWNER ( cardnum varchar(255), NAME varchar(255), OWNER_ID bigint not null, primary key (OWNER_ID)) create table ORMCORE_MAKER ( NAME varchar(255), phone varchar(255), address varchar(255), MAKER_ID bigint not null, primary key (MAKER_ID)) create table ORMCORE_WATCH ( id bigint not null, make varchar(255), model varchar(255), primary key (id)) alter table ORMCORE_MAKER add constraint FKB 91 D 15 CEA 8 DBD 2 F 7 foreign key (MAKER_ID) references ORMCORE_WATCH alter table ORMCORE_OWNER add constraint FKB 943503 D 985 CE 28 foreign key (OWNER_ID) references ORMCORE_WATCH v 130501 Java Persistence: Core ORM 76
Example Multi-Table Mapped Class Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; @Entity @Table(name="ORMCORE_WATCH") @Secondary. Tables({ @Secondary. Table(name="ORMCORE_OWNER", pk. Join. Columns={ @Primary. Key. Join. Column(name="OWNER_ID")}), @Secondary. Table(name="ORMCORE_MAKER", pk. Join. Columns={ @Primary. Key. Join. Column(name="MAKER_ID")}) }) public class Watch implements Serializable { private static final long serial. Version. UID = 1 L; private long id; private String make; private String model; private String owner; private String cardnum; private String manufacturer; private String address; private String phone; v 130501 Java Persistence: Core ORM 77
Enterprise Java Example Multi-Table Mapped Class (cont. ) public Watch() {} public Watch(long id) { this. id = id; } @Id public long get. Id() { return id; } private void set. Id(long id) { this. id = id; } public String get. Make() { return make; } public void set. Make(String make) { this. make = make; } public String get. Model() { return model; } public void set. Model(String model) { this. model = model; } v 130501 Java Persistence: Core ORM 78
Enterprise Java Example Multi-Table Mapped Class (cont. ) @Column(name="NAME", table="ORMCORE_OWNER") public String get. Owner() { return owner; } public void set. Owner(String owner) { this. owner = owner; } @Column(table="ORMCORE_OWNER") public String get. Cardnum() { return cardnum; } public void set. Cardnum(String cardnum) { this. cardnum = cardnum; } @Column(name="NAME", table="ORMCORE_MAKER") public String get. Manufacturer() { return manufacturer; } public void set. Manufacturer(String manufacturer) { this. manufacturer = manufacturer; } v 130501 Java Persistence: Core ORM 79
Enterprise Java Example Multi-Table Mapped Class (cont. ) @Column(table="ORMCORE_MAKER") public String get. Address() { return address; } public void set. Address(String address) { this. address = address; } @Column(table="ORMCORE_MAKER") public String get. Phone() { return phone; } public void set. Phone(String phone) { this. phone = phone; } v 130501 Java Persistence: Core ORM 80
Enterprise Java Example Multi-Table Mapped Class (cont. ) <entity class="ejava. examples. orm. core. mapped. Watch" access="PROPERTY" metadata-complete="true" name="Mapped. Watch"> <table name="ORMCORE_WATCH"/> <secondary-table name="ORMCORE_OWNER"> <primary-key-join-column name="OWNER_ID"/> </secondary-table> <secondary-table name="ORMCORE_MAKER"> <primary-key-join-column name="MAKER_ID"/> </secondary-table> <attributes> <id name="id"/> <basic name="owner"> <column name="NAME" table="ORMCORE_OWNER"/> </basic> <basic name="cardnum"> <column table="ORMCORE_OWNER"/> </basic> <basic name="manufacturer"> <column name="NAME" table="ORMCORE_MAKER"/> </basic> <basic name="address"> <column table="ORMCORE_MAKER"/> </basic> <basic name="phone"> <column table="ORMCORE_MAKER"/> </basic> v 130501 </attributes> Java Persistence: Core ORM </entity> 81
Testing Multi Table Mapping Enterprise Java //leave a watch in DB to inspect Watch watch 3 = new Watch(3); watch 3. set. Make("ontime 3"); watch 3. set. Model("round-and-round 3"); watch 3. set. Owner("john doe 3"); watch 3. set. Cardnum("123 -45 -67893"); watch 3. set. Manufacturer("getter done 3"); watch 3. set. Address("12 noon lane 3"); watch 3. set. Phone("410 -555 -12123"); em. persist(watch 3); log. info("created leftover watch: " + watch 3); select * from ORMCORE_WATCH ID MAKE MODEL 3 ontime 3 round-and-round 3 select * from ORMCORE_MAKER NAME PHONE ADDRESS MAKER_ID getter done 3 410 -555 -12123 12 noon lane 3 3 select * from ORMCORE_OWNER CARDNUM NAME OWNER_ID 123 -45 -67893 john doe 3 3 v 130501 Java Persistence: Core ORM 82
Embedded Objects Enterprise Java • Database Schema create table ORMCORE_XRAY ( id bigint not null, phone varchar(255), address varchar(255), XRAY_MAKER varchar(255), model varchar(255), primary key (id) ) v 130501 Java Persistence: Core ORM 83
Example Embeddable Class Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; @Embeddable public class Manufacturer implements Serializable { private static final long serial. Version. UID = 1 L; private String name; private String address; private String phone; public Manufacturer() {} public Manufacturer(String name, String address, String phone) { this. name = name; this. address = address; this. phone=phone; } v 130501 Java Persistence: Core ORM 84
Example Embeddable Class (cont. ) Enterprise Java public String get. Address() { return address; } public void set. Address(String address) { this. address = address; } public String get. Name() { return name; } public void set. Name(String name) { this. name = name; } public String get. Phone() { return phone; } public void set. Phone(String phone) { this. phone = phone; } v 130501 Java Persistence: Core ORM 85
Example Embeddable orm. xml Enterprise Java <embeddable class="ejava. examples. orm. core. mapped. Manufacturer" access="PROPERTY"> <attributes> <!-- I had to create mapping here --> <basic name="name"> <column name="XRAY_MAKER"/> </basic> <basic name="address"/> <basic name="phone"/> </attributes> </embeddable> v 130501 Java Persistence: Core ORM 86
Example Class with Embedded Object Enterprise Java package ejava. examples. orm. core. annotated; import java. io. Serializable; import javax. persistence. *; @Entity @Table(name="ORMCORE_XRAY") public class XRay implements Serializable { private static final long serial. Version. UID = 1 L; private long id; private Manufacturer maker; private String model; public XRay() {} public XRay(long id) { this. id = id; } @Id public long get. Id() { return id; } private void set. Id(long id) { this. id = id; } v 130501 Java Persistence: Core ORM 87
Example Class with Embedded Object Enterprise Java public String get. Model() { return model; } public void set. Model(String model) { this. model = model; } @Embedded @Attribute. Overrides({ @Attribute. Override(name="name", column=@Column(name="XRAY_MAKER")) //note that we are letting address and phone default }) public Manufacturer get. Maker() { return maker; } public void set. Maker(Manufacturer maker) { this. maker = maker; } v 130501 Java Persistence: Core ORM 88
Enterprise Java Specifying Embedded Object with orm. xml <entity class="ejava. examples. orm. core. mapped. XRay" access="PROPERTY" metadata-complete="true" name="Mapped. XRay"> <table name="ORMCORE_XRAY"/> <attributes> <id name="id"/> <embedded name="make"> <!-- this was being ignored --> <attribute-override name="name"> <column name="XRAY_MAKER"/> </attribute-override> <!-- address and phone will default to a column name --> </embedded> <!-- model will default to a column name --> </attributes> </entity> v 130501 Java Persistence: Core ORM 89
Testing Embedded Object Enterprise Java //leave an xray in DB to inspect XRay xray 3 = new XRay(3); xray 3. set. Model("inside-counts"); xray 3. set. Maker( new Manufacturer("hi-tech", "low valley", "410 -555 -1212")); em. persist(xray 3); log. info("created leftover xray: " + xray 3); select * from ORMCORE_XRAY ID PHONE ADDRESS XRAY_MAKER MODEL -- ------------3 410 -555 -1212 low valley hi-tech inside-counts v 130501 Java Persistence: Core ORM 90
Enterprise Java Using the Provider to Generate DB Schema v 130501 Java Persistence: Core ORM 91
Generating Schema at Runtime Enterprise Java • persistence. xml <properties>. . . <property name="hibernate. hbm 2 ddl. auto" value="create"/> </properties> – quick and easy – fine for examples and prototypes – not likely to be suitable for operational use v 130501 Java Persistence: Core ORM 92
Generating Schema at Compile Time Enterprise Java <properties> <hibernate 3 -maven-plugin. version>3. 0</hibernate 3 -maven-plugin. version> <properties> <build> <plugins> <plugin> <group. Id>org. codehaus. mojo</group. Id> <artifact. Id>hibernate 3 -maven-plugin</artifact. Id> <version>${hibernate 3 -maven-plugin. version}</version> <extensions>true</extensions> <dependencies> <dependency> <group. Id>org. hibernate</group. Id> <artifact. Id>hibernate-entitymanager</artifact. Id> <version>${hibernate 3. version}</version> </dependency> </dependencies> <executions>. . . </executions> <configuration>. . . </configuration> </plugin> <plugins> </build> v 130501 Java Persistence: Core ORM 93
Generating Schema at Compile Time Enterprise Java <executions> <execution> <id>generate-drop-ddl</id> <phase>process-test-resources</phase> <goals> <goal>run</goal> </goals> <configuration> <hibernatetool> <hbm 2 ddl export="false" create="false" drop="true" format="true" outputfilename="${project. artifact. Id}-drop. JPA. ddl"/> </hibernatetool> </configuration> </execution> <id>generate-create-ddl</id> <phase>process-test-resources</phase> <goals> <goal>run</goal> </goals> <configuration> <hibernatetool> <hbm 2 ddl export="false" create="true" drop="false" format="true" outputfilename="${project. artifact. Id}-create. JPA. ddl"/> </hibernatetool> </configuration> </executions> v 130501 Java Persistence: Core ORM 94
Generating Schema at Compile Time Enterprise Java <build> <plugins> <plugin> <artifact. Id>hibernate 3 -maven-plugin</artifact. Id> <group. Id>org. codehaus. mojo</group. Id> <configuration> <hibernatetool destdir="target/classes/ddl"> <classpath> <path location="${project. build. directory}/test-classes"/> </classpath> <jpaconfiguration persistenceunit=" orm. Core" propertyfile= "${basedir}/target/test-classes/hibernate. properties"/> </hibernatetool> </configuration> </plugins> </build> v 130501 Java Persistence: Core ORM 95
Generated Output Enterprise Java • Files are generated during specified Maven build phase <phase>process-test-resources</phase> – above means plugin will run after classes are compiled and resource files are copied/filtered to target tree • DDL is generated to the specified output. Directory <output. Directory>target/classes/ddl</output. Directory> • Files are named according to specified outputfilename <outputfilename>${pom. artifact. Id}-create. JPA. ddl</outputfilename> target/classes/. . . |-- ddl | |-- orm. Core-create. JPA. ddl | `-- orm. Core-drop. JPA. ddl • Files can be used for – manual schema creation – comparing against legacy schema v 130501 Java Persistence: Core ORM 96
Summary Enterprise Java • Entities – POJOs – optionally contain mapping annotations – optionally use of orm. xml for mapping annotations • metadata-complete – turns off class annotations – field or property access • Primary Key Generation – AUTO – required – TABLE – ids derived from user named table – SEQUENCE – ids generated from database managed table – IDENTITY – leverage table identity generation • Primary Keys – simple – composite • Id. Class – external mapping to class • Embedded. Id – incorporated into class v 130501 Java Persistence: Core ORM 97
Summary (cont. ) Enterprise Java • Fine Tuning – Transient • tell persistence provider to ignore this property – Fetch. Type • hint to persistence provider whether eager or lazy load of property would be appropriate for intended use of object – Temporal • specifying guidance for mapping Date and Calendar properties – Lob • mapping BLOB and CLOB types – Enumerated • mapping Java SE 5 Enumerated types • Multi-table Mappings – Secondary Tables – split object into multiple tables – Embedded Objects – collapse objects into single table v 130501 Java Persistence: Core ORM 98
References Enterprise Java • “Enterprise Java. Beans 3. 0, 5 th Edition”; Burke & Monsen-Haefel; ISBN 0 -596 -00978 -X; O'Reilly v 130501 Java Persistence: Core ORM 99
- Slides: 99