OneToOne mapping not working: EntityA.entityB referencing EntityB not mapped to a single property
I have two entities, EntityA and EntityB.
EntityA has a composite primary key on two fields: id and flag.
EntityB also has a composite primary key on two fields: id and flag.
The two entities are linked with a common field / column: entityBKey. (This is a foreign key but not explicitly defined as such at the database level, if that makes a difference. Old design can’t really change much)
This is how I am calling EntityA:
CriteriaBuilder builder = session.getCriteriaBuilder();
CriteriaQuery<EntityA> criteriaQuery = builder.createQuery(EntityA.class);
Root<EntityA> from = criteriaQuery.from(EntityA.class);
criteriaQuery.select(from);
But I get this error on application boot:
EntityA.entityB referencing EntityB not mapped to a single property
at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:203)
at org.hibernate.cfg.ToOneFkSecondPass.doSecondPass(ToOneFkSecondPass.java:104)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processEndOfQueue(InFlightMetadataCollectorImpl.java:1750)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processFkSecondPassesInOrder(InFlightMetadataCollectorImpl.java:1694)
at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1623)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295)
at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:86)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:479)
at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:709)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:746)
In some places I have read it says that non-primary keys can be referenced by using the referencedColumnName attribute but it is clearly not working.
Any ideas what I can do here? Much appreciated.
EntityA:
@Entity
@Table(name = "EntityA")
@IdClass(KeyClass.class)
public class EntityA implements Serializable {
@Id
@Column(name = "id", nullable = false)
protected Integer id = null;
@Id
@Column(name = "flag", nullable = false)
protected Integer flag = null;
@Column(name = "EntityAKey", nullable = false)
private String entityAKey = null;
@Column(name = "EntityBKey", nullable = false)
private String entityBKey = null;
@OneToOne(mappedBy="entityA")
private EntityB entityB;
public EntityA() {
super();
}
}
EntityB:
@Entity
@Table(name = "EntityB")
@IdClass(KeyClass.class)
public class EntityB implements Serializable {
@Id
@Column(name = "id", nullable = false)
protected Integer id = null;
@Id
@Column(name = "flag", nullable = false)
protected Integer flag = null;
@Column(name = "EntityBKey", nullable = false)
private String entityBKey = null;
@OneToOne(cascade = CascadeType.ALL)
@JoinColumns({
@JoinColumn(name = "entityBKey", referencedColumnName = "entityBKey", insertable = false, updatable = false),
@JoinColumn(name = "flag", referencedColumnName = "flag", insertable = false, updatable = false)}
)
@Where(clause = "flag=1")
private EntityA entityA;
public EntityB() {
super();
}
}
KeyClass:
public class KeyClass implements Serializable {
private Integer id = null;
private Integer flag = null;
public KeyClass() {
}
public KeyClass(Integer id, Integer flag) {
this.id = id;
this.flag = flag;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getFlag() {
return flag;
}
public void setFlag(Integer flag) {
this.flag = flag;
}
@Override
public boolean equals(Object o) {
...
}
@Override
public int hashCode() {
...
}
}