The blog records how to map two entities by the composite keys by using hibernate. Let's say we have 2 entities PrizeItem
and PrizeWinnerInfo
. We want to map them as OneToOne relation.
The PrizeWinnerInfo
(pzwininfo_pzitem_pz_id, pzwininfo_pzitem_id) refer to PrizeItem
(pzitem_pz_id, pzitem_id) with the composite foreign key.
Step 0.
Database schema of PrizeItem
, table name: ix_prize_item
+----------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+--------------+------+-----+---------+-------+
| pzitem_pz_id | bigint(20) | NO | PRI | NULL | |
| pzitem_id | int(11) | NO | PRI | NULL | |
| pzitem_expiration | datetime | YES | | NULL | |
| pzitem_won | tinyint(1) | NO | | 0 | |
| pzitem_won_time | datetime | YES | | NULL | |
| pzitem_winner_info_applied | tinyint(1) | NO | | 0 | |
| pzitem_pzcha_id | int(11) | YES | MUL | NULL | |
| pzitem_serial | varchar(255) | YES | | NULL | |
+----------------------------+--------------+------+-----+---------+-------+
Database schema of PrizeWinnerInfo
, table name: ix_prize_winner_info
+------------------------+--------------+------+-----+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+------------------------+--------------+------+-----+---------+-------+
| pzwininfo_pzcha_id | int(11) | NO | MUL | 0 | |
| pzwininfo_pzitem_pz_id | bigint(20) | NO | PRI | 0 | |
| pzwininfo_pzitem_id | int(11) | NO | PRI | 0 | |
| pzwininfo_name | varchar(255) | NO | | NULL | |
| pzwininfo_email | varchar(128) | NO | | NULL | |
| pzwininfo_phone | varchar(32) | YES | | NULL | |
| pzwininfo_detail | longtext | YES | | NULL | |
+------------------------+--------------+------+-----+---------+-------+
Step 1.
Tip: Use @Embeddable
to define the composite key
The composite primary key PrizeItemPK
of PrizeItem
@Embeddable
public class PrizeItemPK implements Serializable
{
private final static long serialVersionUID = 1L;
@Column(name="pzitem_pz_id")
private Long prizeId;
@Column(name="pzitem_id")
private Integer prizeItemId;
public PrizeItemPK() {}
public PrizeItemPK(Long prizeId, Integer prizeItemId) {
super();
this.prizeId = prizeId;
this.prizeItemId = prizeItemId;
}
@JsonGetter("prize_id")
public Long getPrizeId() {
return prizeId;
}
public void setPrizeId(Long prizeId) {
this.prizeId = prizeId;
}
@JsonGetter("prize_item_id")
public Integer getPrizeItemId() {
return prizeItemId;
}
public void setPrizeItemId(Integer prizeItemId) {
this.prizeItemId = prizeItemId;
}
}
The composite primary key PrizeWinnerInfoPK
of PrizeWinnerInfo
@Embeddable
public class PrizeWinnerInfoPK implements Serializable
{
private final static long serialVersionUID = 1L;
@Column(name="pzwininfo_pzitem_pz_id")
private Long prizeId;
@Column(name="pzwininfo_pzitem_id")
private Integer prizeItemId;
public PrizeWinnerInfoPK() {}
public PrizeWinnerInfoPK(Long prizeId, Integer prizeItemId) {
super();
this.prizeId = prizeId;
this.prizeItemId = prizeItemId;
}
@JsonGetter("prize_id")
public Long getPrizeId() {
return prizeId;
}
public void setPrizeId(Long prizeId) {
this.prizeId = prizeId;
}
@JsonGetter("prize_item_id")
public Integer getPrizeItemId() {
return prizeItemId;
}
public void setPrizeItemId(Integer prizeItemId) {
this.prizeItemId = prizeItemId;
}
}
Step2.
Tip1: Use @OneToMany
mapping, not @OneToOne
Tip2: Use @JsonManagedReference
and @JsonBackReference
to avoid cycling json serialization
ORM entity of PrizeItem
@Entity
@Table(name="ix_prize_item")
@JsonAutoDetect(getterVisibility=JsonAutoDetect.Visibility.NONE)
public class PrizeItem
{
@EmbeddedId
private PrizeItemPK pk;
...
@OneToMany(mappedBy="prizeItem", fetch=FetchType.EAGER)
@JsonBackReference
private List winnerInfo;
}
ORM entity of PrizeWinnerInfo
@Entity
@Table(name="ix_prize_winner_info")
@JsonAutoDetect(getterVisibility=JsonAutoDetect.Visibility.NONE)
public class PrizeWinnerInfo extends AbstractExtensibleJsonAliasBean
{
@EmbeddedId
private PrizeWinnerInfoPK PK;
...
@ManyToOne(fetch=FetchType.EAGER)
@JoinColumns ({
@JoinColumn(name="pzwininfo_pzitem_pz_id", referencedColumnName = "pzitem_pz_id", insertable = false, updatable = false),
@JoinColumn(name="pzwininfo_pzitem_id", referencedColumnName = "pzitem_id", insertable = false, updatable = false)
})
@JsonManagedReference
private PrizeItem prizeItem;
}
2014/01/16 Note:
I found the use of @JsonBackReference
will make the serialization fail on that field. So, I took the below solution (http://stackoverflow.com/a/10111411/474002)
References:
- java - hibernate composite Primary key contains a composite foreign key, how to map this - Stack Overflow
- java - @OneToOne annotation within composite key class is not working - Stack Overflow
- @JoinColumn is part of the composite primary keys | dwuysan