Issue
I have discovered some strange behavior with Hibernate. I have a One to Many relationship between two entities that use embedded composite primary keys like this. (and yes, I know the data design is awful, but this is the schema I have to work with)
@Entity
@Table(name = "T_PLACE")
public class Place {
@EmbeddedId
private PlacePK id;
@OneToMany(mappedBy = "place")
private List<Mode> modes;
// getters and setters
}
@Embeddable
public class PlacePK implements Serializable {
@Column(name = "COMPANY")
private String company;
@Column(name = "AREA")
private String area;
@Column(name = "COLOR")
private String color;
// getters and setters
}
@Entity
@Table(name = "T_MODE")
public class Mode {
@EmbeddedId
private ModePK id;
@ManyToOne
@JoinColumns({
@JoinColumn(name = "COMPANY", insertable = false, updatable = false),
@JoinColumn(name = "AREA", insertable = false, updatable = false),
@JoinColumn(name = "COLOR", insertable = false, updatable = false),
})
private Place place;
private String function;
// getters and setters
}
@Embeddable
public class ModePK implements Serializable {
@Column(name = "COMPANY")
private String company;
@Column(name = "AREA")
private String area;
@Column(name = "COLOR")
private String color;
@Column(name = "MODE_ID")
private String color;
// getters and setters
}
But the resulting HQL ends up ordering it like this when querying for a place's modes
where
company=?
and color=?
and area=?
and it ends up binding area to the second ?
and color to the third ?
.
It doesn't work unless I change the order of the @JoinColumn
s to put color before area.
@JoinColumns({
@JoinColumn(name = "COMPANY", insertable = false, updatable = false),
@JoinColumn(name = "COLOR", insertable = false, updatable = false),
@JoinColumn(name = "AREA", insertable = false, updatable = false),
})
So my question is, what is causing this behavior? What determines the order of the where clause in the HQL? This isn't any issue because I've figured out how to make it work, but I'd like to understand it.
I am using spring-boot-starter-data-jpa:1.5.10-RELEASE
which uses Hibernate 5.
Edit
Here is how I'm producing the HQL
@Repository
public interface PlaceRepository extends JpaRepository<Place, PlacePK> {}
and then in a test:
PlacePK placePK = new PlacePK();
placePK.setCompany("Acme");
placePK.setArea("XYZ");
place.PK.setColor("Blue");
Place place = placeRepository.findOne(placePK);
List<Mode> modes = place.getModes(); // ends up being an empty PersistBag until I switch the order of the @JoinColumns
assertNotNull(modes);
Solution
The order mattes because based on this order Hibernate builds a join condition. Hibernate doesn't know how to map specific columns to each other (even though, it could do it through naming comparison, but...). So it does it by simply putting them in the same order as you specified versus the ID columns.
To see what difference ordering does, switch on logging on the produced SQL queries. You will see that if you order is not aligned with the order of the ID keys, your fetch query may end up in something like
...join PlacePK pk ON pk.COMPANY = m.AREA*emphasized text*
Answered By - Andremoniy
Answer Checked By - Robin (JavaFixing Admin)