Enterprise Java Development@TOPIC@
Primary key consisting of multiple properties
Represented using a primary key class
Must implement Serializable
public class MowerPK implements Serializable {
Must have a public no-arg constructor
public MowerPK() {}
Must implement hashCode() and equals() methods
@Override
public int hashCode() { ... }
@Override
public boolean equals(Object obj) { ... }
Must define properties that match with the definition of the entity, including access
private String make; private String model;
Accessed using same strategy as entity using it
package ejava.examples.orm.core;
import java.io.Serializable;
public class MowerPK implements Serializable {
private static final long serialVersionUID = 1L;
private String make;
private String model;
public MowerPK() {}
public MowerPK(String make, String model) {
this.make = make;
this.model = model;
}
public String getMake() { return make; }
public String getModel() { return model; }
@Override
public int hashCode() { return make.hashCode() + model.hashCode(); }
@Override
public boolean equals(Object obj) {
try {
if (this == obj) return true;
return make.equals(((MowerPK)obj).getMake()) &&
model.equals(((MowerPK)obj).getModel());
} catch (Throwable ignored) { //catch NP & Cast Exceptions
return false;
}
}
...
}
A class separate from the entity that independently models PK properties
No reference to the @IdClass within the entity
Figure 49.1. Composite @IdClass Database Schema
create table ORMCORE_MOWER ( make varchar(255) not null, model varchar(255) not null, size integer not null, primary key (make, model) )
Figure 49.2. Composite @IdClass Example Usage
@Entity
@Table(name="ORMCORE_MOWER")
@IdClass(MowerPK.class)
public class Mower {
@Id
private String make;
@Id
private String model;
private int size;
public Mower() {}
public Mower(String make, String model) {
this.make = make;
this.model = model;
}
public String getMake() { return make; }
public String getModel() { return model; }
Figure 49.3. Composite @IdClass Example orm.xml
<entity class="ejava.examples.orm.core.mapped.Mower" access="FIELD">
<table name="ORMCORE_MOWER"/>
<id-class class="ejava.examples.orm.core.MowerPK"/>
<attributes>
<id name="make"/>
<id name="model"/>
</attributes>
</entity>
Figure 49.4. Composite @IdClass Example Client
Create Entity with Composite ID
ejava.examples.orm.core.annotated.Mower mower = new Mower("acme", "power devil2");
mower.setSize(21);
//insert a row in the database
logger.info("persisting mower(tx={}): {}", txActive(), mower);
em.persist(mower);
logger.info("created mower: {}", mower);
em.flush();
logger.info("flushed");
-persisting mower(tx=true): 1756435781, make=acme, model=power devil2, size=21
-created mower: 1756435781, make=acme, model=power devil2, size=21
-insert into ORMCORE_MOWER (size, make, model) values (?, ?, ?)
-binding parameter [1] as [INTEGER] - [21]
-binding parameter [2] as [VARCHAR] - [acme]
-binding parameter [3] as [VARCHAR] - [power devil2]
-flushed
Get Instance by Composite ID
//locate instance by ID, while instance still managed
Mower mower2 = em.find(Mower.class, new MowerPK("acme", "power devil2"));
assertNotNull(mower2);
logger.info("found mower: {}", mower2);
assertEquals(mower.getSize(), mower2.getSize());
-found mower: 1756435781, make=acme, model=power devil2, size=21
Instance is found in cache by ID without having to query database
Remove Instance from Database
em.remove(mower2);
logger.info("removed mower: {}", mower2);
em.flush();
logger.info("removed mower after flush: {}", mower2);
Mower mower3 = em.find(Mower.class, new MowerPK("acme", "power devil2"));
assertNull(mower3);
-removed mower: 1756435781, make=acme, model=power devil2, size=21
-delete from ORMCORE_MOWER
where make=? and model=?
-binding parameter [1] as [VARCHAR] - [acme]
-binding parameter [2] as [VARCHAR] - [power devil2]
-removed mower after flush: 1756435781, make=acme, model=power devil2, size=21
-select mower0_.make as make1_7_0_, mower0_.model as model2_7_0_, mower0_.size as size3_7_0_
from ORMCORE_MOWER mower0_
where mower0_.make=? and mower0_.model=?
-binding parameter [1] as [VARCHAR] - [acme]
-binding parameter [2] as [VARCHAR] - [power devil2]
Row removed from database and instance detached
Primary key used to query database since instance no longer in cache
A class that hosts the primary key properties
Contained/"embedded" within the entity class
Figure 49.5. @EmbeddedId Example 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)
)
Figure 49.6. @Embeddable Primary Key Class
package ejava.examples.orm.core.mapped;
import java.io.Serializable;
import javax.persistence.*;
@Embeddable
public class NapsackPK implements Serializable {
private static final long serialVersionUID = 1L;
@Column(name="NAPSACK_MAKE") //maps field to column of containing class
private String make;
@Column(name="NAPSACK_MODEL")//maps field to column of containing class
private String model;
public NapsackPK() {}
public NapsackPK(String make, String model) {
this.make = make;
this.model = model;
}
public String getMake() { return make; }
public String getModel() { return model; }
public int hashCode() { return make.hashCode() + model.hashCode(); }
public boolean equals(Object obj) {
try {
if (this == obj) return true;
return make.equals(((NapsackPK)obj).getMake()) &&
model.equals(((NapsackPK)obj).getModel());
} catch (Throwable ignored) { //catch NP & Cast Exceptions
return false;
}
}
Figure 49.7. Composite @EmbeddedId Example Usage
@Entity
@Table(name="ORMCORE_NAPSACK")
public class Napsack {
@EmbeddedId
private NapsackPK pk;
private int size;
public Napsack() {}
public Napsack(String make, String model) {
this.pk = new NapsackPK(make, model);
}
public NapsackPK getPk() { return pk; }
...
Figure 49.8. Composite @EmbeddedId Example orm.xml
<entity class="ejava.examples.orm.core.mapped.Napsack" access="FIELD">
<table name="ORMCORE_NAPSACK"/>
<attributes>
<embedded-id name="pk"/>
</attributes>
</entity>
<embeddable class="ejava.examples.orm.core.mapped.NapsackPK">
<attributes>
<basic name="make">
<column name="NAPSACK_MAKE"/>
</basic>
<basic name="model">
<column name="NAPSACK_MODEL"/>
</basic>
</attributes>
</embeddable>
Supply or override mapping of primary key class by entity class
Figure 49.9. Example Overridden @Embeddable PK Class
@Embeddable
public class MakeModelPK implements Serializable {
private String make;
private String model;
Figure 49.10. Example Overridden @Embeddable Entity 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) )
Figure 49.11. Example Overridden @Embeddable Entity Class
@Entity
@Table(name="ORMCORE_PEN")
public class Pen {
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name="make", column=@Column(name="PEN_MAKE")),
@AttributeOverride(name="model", column=@Column(name="PEN_MODEL"))
})
private MakeModelPK pk;
private int size;
public Pen() {}
public Pen(String make, String model) {
this.pk = new MakeModelPK(make, model);
}
public MakeModelPK getPk() { return pk; }
Figure 49.12. Example Overridden @Embeddableorm.xml
<entity class="ejava.examples.orm.core.mapped.Pen" access="FIELD">
<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.MakeModelPK">
<attributes>
<basic name="make"/>
<basic name="model"/>
</attributes>
</embeddable>
PKClass Requirements
Serializable
No-arg constructor
hashCode() and equals()
PK properties
@IdClass
Independent class containing copy of entity PK properties
@Embeddable
Class instance containing entity PK properties -- embedded within entity
DB Mapping
Primary in PKClass
Overrides in Entity class
@AttributeOverrides