Enterprise Java Development@TOPIC@
This chapter will take you through mapping a set of two or more natural fields as a compound primary key. Nothing is being generated with natural/compound keys. We are combining multiple fields to represent the object's identity.
A compound primary key is required to...
Be Serializable
Have a default constructor (either built-in or declared)
Supply a hash() and equals() method
Provide public access to
Create an instance of the following JPA primary key class in your src/main tree.
package myorg.entityex.annotated;
import java.io.Serializable;
import javax.persistence.*;
@Embeddable
public class CowPK implements Serializable { //required to be Serializable
private static final long serialVersionUID = 1L;
private String herd;
private String name;
public CowPK(){} //required default ctor
public CowPK(String herd, String name) {
this.herd = herd;
this.name = name;
};
public String getHerd() { return herd; }
public String getName() { return name; }
@Override
public int hashCode() { //required hashCode method
return herd.hashCode() + name.hashCode();
}
@Override
public boolean equals(Object obj) { //required equals method
try {
return herd.equals(((CowPK)obj).herd) &&
name.equals(((CowPK)obj).name);
} catch (Exception ex) {
return false;
}
}
}
package myorg.entityex.annotated;
import javax.persistence.*;
@Entity
@Table(name="ENITYEX_COW")
public class Cow {
@EmbeddedId
private CowPK pk;
private int weight;
public Cow() {}
public Cow(CowPK cowPK) {
this.pk = cowPK;
}
public CowPK getPk() { return pk; }
public void setPk(CowPK pk) {
this.pk = pk;
}
public int getWeight() { return weight; }
public void setWeight(int weight) {
this.weight = weight;
}
}
Add the new entity class to your persistence unit.
<class>myorg.entityex.annotated.Cow</class>
create table Cow ( herd varchar(255) not null, name varchar(255) not null, weight integer not null, primary key (herd, name) );
@Column(name="HERD", length=16)
private String herd;
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name="name", column=@Column(name="NAME", length=16))
})
private CowPK pk;
create table Cow ( HERD varchar(16) not null, NAME varchar(16) not null, weight integer not null, primary key (HERD, NAME) );
Add the following test method to your JUnit test case
@Test
public void testEmbeddedId() {
log.info("testEmbedded");
Cow cow = new Cow(new CowPK("Ponderosa", "Bessie"));
cow.setWeight(900);
em.persist(cow);
//flush to DB and get a new instance
em.flush(); em.detach(cow);
Cow cow2 = em.find(Cow.class, new CowPK("Ponderosa", "Bessie"));
assertNotNull("cow not found", cow2);
assertEquals("unexpected herd", cow.getPk().getHerd(), cow2.getPk().getHerd());
assertEquals("unexpected name", cow.getPk().getName(), cow2.getPk().getName());
assertEquals("unexpected weight", cow.getWeight(), cow2.getWeight());
}
$ mvn clean test -Ph2srv -P\!h2db ... -testEmbedded Hibernate: insert into ENITYEX_COW (weight, HERD, NAME) values (?, ?, ?) Hibernate: select cow0_.HERD as HERD5_0_, cow0_.NAME as NAME5_0_, cow0_.weight as weight5_0_ from ENITYEX_COW cow0_ where cow0_.HERD=? and cow0_.NAME=? ... [INFO] BUILD SUCCESS SELECT * FROM ENITYEX_COW; HERD NAME WEIGHT Ponderosa Bessie 900
Put the following entity class in place in your src/main tree.
package myorg.entityex.annotated;
import javax.persistence.*;
@Entity
@Table(name="ENITYEX_COW2")
@IdClass(CowPK.class)
@AttributeOverrides({
@AttributeOverride(name="name", column=@Column(name="NAME", length=16))
})
public class Cow2 {
@Id
private String herd;
@Id
private String name;
private int weight;
public Cow2() {}
public Cow2(String herd, String name) {
this.herd = herd;
this.name = name;
}
public String getHerd() { return herd; }
public String getName() { return name; }
public int getWeight() { return weight; }
public void setWeight(int weight) {
this.weight = weight;
}
}
Add the new entity class to the persistence unit.
<class>myorg.entityex.annotated.Cow2</class>
create table ENITYEX_COW2 ( HERD varchar(16) not null, NAME varchar(16) not null, weight integer not null, primary key (HERD, NAME) );
Add the following test method for the new entity class to your existing Junit test case.
@Test public void testIdClass() { log.info("testIdClass"); Cow2 cow = new Cow2("Ponderosa", "Bessie"); cow.setWeight(900); em.persist(cow); //flush to DB and get a new instance em.flush(); em.detach(cow); Cow2 cow2 = em.find(Cow2.class, new CowPK("Ponderosa", "Bessie")); assertNotNull("cow not found", cow2); assertEquals("unexpected herd", cow.getHerd(), cow2.getHerd()); assertEquals("unexpected name", cow.getName(), cow2.getName()); assertEquals("unexpected weight", cow.getWeight(), cow2.getWeight()); }
$ mvn clean test -Ph2srv -P\!h2db ... -testIdClass Hibernate: insert into ENITYEX_COW2 (weight, HERD, NAME) values (?, ?, ?) Hibernate: select cow2x0_.HERD as HERD6_0_, cow2x0_.NAME as NAME6_0_, cow2x0_.weight as weight6_0_ from ENITYEX_COW2 cow2x0_ where cow2x0_.HERD=? and cow2x0_.NAME=? ... [INFO] BUILD SUCCESS SELECT * FROM ENITYEX_COW2; HERD NAME WEIGHT Ponderosa Bessie 900