1
votes

I am going through the Hibernate documentation for bidirectional relationship, in the doc it says that:

Example 7.21. Bidirectional one to many with many to one side as association owner

@Entity
public class Troop {
    @OneToMany(mappedBy="troop")
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk")
    public Troop getTroop() {
    ...
}   

Troop has a bidirectional one to many relationship with Soldier through the troop property. You don't have to (must not) define any physical mapping in the mappedBy side.

To map a bidirectional one to many, with the one-to-many side as the owning side, you have to remove the mappedBy element and set the many to one @JoinColumn as insertable and updatable to false. This solution is not optimized and will produce additional UPDATE statements.

Example 7.22. Bidirectional association with one to many side as owner

@Entity
public class Troop {
    @OneToMany
    @JoinColumn(name="troop_fk") //we need to duplicate the physical information
    public Set<Soldier> getSoldiers() {
    ...
}

@Entity
public class Soldier {
    @ManyToOne
    @JoinColumn(name="troop_fk", insertable=false, updatable=false)
    public Troop getTroop() {
    ...
}

I am finding difficulty in understanding this as I am new to Hibernate.

1) What it means when the doc says: You don't have to (must not) define any physical mapping in the mappedBy side.

2) @JoinColumn in 7.22 has same value (troop_fk) for name attribute. Can we specify different values? What is the advantage & disadvantages of setting insertable=false, updatable=false here?

Can someone please explain?

1

1 Answers

3
votes

It's a bidirectional association. So, if a soldier balongs to a troop, the troop contains the soldier. These are just the two ways of saying the same thing.

In Soldier, you tell how the association is represented in the database: using a join column named troop_fk:

@JoinColumn(name="troop_fk")
public Troop getTroop() {

So, repeating that same information on the other side of this bidirectional association is redundant. You must not do it. By saying

@OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {

you're telling Hibernate that getSoldiers() is the inverse side of a bidirectional association, and that the way this association is mapped can be found on the Soldier.troop property.

Regarding your second question. Once again, the goal is to define a single, but bidirectional association. You don't need two different foreign keys to map a single association. So specifying a different name for the join column would make no sense: it would create a different, unidirectional association.

This way of doing is an ugly hack that, AFAIK, is not supported by the JPA spec. The JPA spec mandates that the owner side of a bidirectional OneToMany association is the many side. In fact it creates two unidirectional associations mapped the same way, and tells Hibernate (using insertable = false and updatable = false) to ignore one of them when saving the entity. It will populate soldier.troop when reading a soldier from the database, but whatever you put into soldier.troop will be ignored when saving the soldier. You should avoid this way of doing, IMHO.