I'm working with three object, let's call them Who, What, Where. Their intersection is unique and requires a fourth entity: WhatWhere. I'm struggling with how to setup the classes and annotations to make this work. Note, the What and the Where are unidirectional; they're just lookup tables.
public class Who {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long whoId;
@OneToMany(mappedBy = "whoId", fetch = FetchType.EAGER)
private List<WhatWhere> whatWhere;
}
public class What {
@Id
@Nationalized
@Column(name = "whatId",length = 3)
private String whatId;
}
public class Where {
@Id
private Integer whereId;
}
At this point, I've seen two strategies for the joining entity: either make it a @IdClass
@IdClass(WhatWhere.class)
public class WhatWhere implements Serializable {
@ManyToOne
@JoinColumn(insertable = false, updatable = false, name = "whoId")
private Who who;
@ManyToOne
@JoinColumn(insertable = false, updatable = false, name = "whatId")
private What what;
@ManyToOne
@JoinColumn(insertable = false, updatable = false, name = "whereId")
private Where where;
}
or create an @EmbeddedId
.
public class WhatWhere {
@Embeddable
public static class WhatWherePK implements Serializable {
@Column(nullable = false, updatable = false, name = "whoId")
private Long whoId;
@Column(nullable = false, updatable = false, length = 3, name = "whatId")
private String whatId;
@Column(nullable = false, updatable = false, name = "whereId")
private Integer whereId;
}
@EmbeddedId
private WhatWherePK pk;
@ManyToOne
@JoinColumn(insertable = false, updatable = false)
private Who who;
@ManyToOne
@JoinColumn(insertable = false, updatable = false)
private What what;
@ManyToOne
@JoinColumn(insertable = false, updatable = false)
private Where where;
}
Related: what is the expected way to populate and persist these objects? I am attempting this approach
public void doSave(What what, Where where){ // assumes 2 objects with ids
Who who = new Who();
whoRepository.save(who); // gets an id from the db
WhatWhere whatWhere = new WhatWhere();
whatWhere.setWho(who);
whatWhere.setWhat(what);
whatWhere.setWhere(where);
whatWhereRepository.save(whatWhere); // expect it to composite pk
}
However, if I have the objects mapped with as @IdClass
, the JPA Repository give an error about failing to convert one of the objects into its respective @Id
field type. OTOH, when it's configured to use an @EmbeddedId
, it would appear that I have to populate the PK class as well? That seems like a lot of procedural effort - is Hibernate not able to infer that wiring?
The application is using Spring Boot 2.3.2 and Hibernate 5.4.2