A composite Id consists of multiple database columns mapped to a id class. There are two options to map a composite Id:
Important: You must overwrite equals and hashCode for composite id classes. If not Hibernate will think that the following id classes are different.
BoxTurtleId b1 = new BoxTurtleId("Bad Vilbel", "Roman salad");
BoxTurtleId b2 = new BoxTurtleId("Bad Vilbel", "Roman salad");
b1.equals(b2);Eclipse and probably most IDEs provides a generator function for this. In Eclipse it is right click on the source → source → Generate hashCode, equals. You will find a detailed explanation about equals and hashCode in the next chapter.
Let’s have a look at an example: The famous box turtle for example can be clearly identified by its locations and the favourite salad. We will map it with an @EmbeddedId.

BoxTurtle class.
import java.io.Serializable;
import javax.persistence.EmbeddedId;
import javax.persistence.Entity;
@Entity
public class BoxTurtle implements Serializable {
@EmbeddedId
private BoxTurtleId id;
Id class.
import java.io.Serializable;
public class BoxTurtleId implements Serializable {
private String location;
private String favoriteSalad;
The primary key fields are included in the Id class. The BoxTurtle class only references the Id class.
BoxTurtle.hbm.xml.
<class name="BoxTurtle" table="boxturtle">
<composite-id class="BoxTurtleId" name="id">
<key-property name="favouriteSalad"></key-property>
<key-property name="location"></key-property>
</composite-id>
......... snip .........
Usage examples.
/* save/create a box turtle */
BoxTurtleId boxTurtleId = new BoxTurtleId("Bad Vilbel", "Roman salad");
BoxTurtle boxTurtle = new BoxTurtle();
boxTurtle.setId(boxTurtleId);
session.save(boxTurtle);
/* get a box turtle from db */
BoxTurtleId boxTurtleId = new BoxTurtleId("Bad Vilbel", "Roman salad");
BoxTurtle boxTurtleReloaded = (BoxTurtle) session.get(
BoxTurtle.class, boxTurtleId);
/* find a box turtle */
List<BoxTurtle> turtles = session.createQuery(
"from BoxTurtle b where b.id.favouriteSalad = :salad")
.setString("salad", "Roman salad").list();
The SpottetTurtle is totally different from its outlook but can identified by its location and its favourite salad as well. We will map it as @IdClass. The main difference is that the fields location and favoriteSalad are included in the Turtle class and the Id class. I recommend the first approach, as it provides less redundancy and is clearer in the class model.
| Classes | Tables |
|---|---|
|
|
SpottedTurtle class.
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
@Entity
@IdClass(SpottedTurtleId.class)
public class SpottedTurtle implements Serializable {
@Id
private String location;
@Id
private String favoriteSalad;
SpottedTurtleId.
import java.io.Serializable;
import de.laliluna.utils.ClassUtils;
public class SpottedTurtleId implements Serializable {
private String location;
private String favoriteSalad;
The same as XML mapping:
<class name="SpottedTurtle" table="spottedturtle">
<composite-id class="SpottedTurtleId" mapped="true">
<key-property name="favouriteSalad"></key-property>
<key-property name="location"></key-property>
</composite-id>
........ snip ..........Usage examples.
/* create or save a turtle */
SpottedTurtle spottedTurtle = new SpottedTurtle("Leipzig",
"Greek salad", "Daniel");
session.save(spottedTurtle);
/* get a box turtle from db */
SpottedTurtleId spottedTurtleId = new SpottedTurtleId("Leipzig",
"Greek salad");
SpottedTurtle spottedTurtleReloaded = (SpottedTurtle) session.get(
SpottedTurtle.class, spottedTurtleId);
/* find a box turtle */
List<SpottedTurtle> turtles = session.createQuery(
"from SpottedTurtle b where b.favouriteSalad = :salad")
.setString("salad", "Roman salad").list();