Composite Id

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.

Class and Table of Embedded ID

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.

Same as XML mapping:

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

images/c_annotation_composite_id2_class.jpg

images/c_annotation_composite_id2_table.jpg

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();