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