Given A class
@Entity
@Table(name = "ATABLE")
public class A implements Serializable {
public static final String DB_ID = "AID";
public static final String DB_MARKET = "AMARKET";
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "id", column = @Column(name = DB_ID)),
@AttributeOverride(name = "market", column = @Column(name = DB_MARKET))
})
public AIdClass id;
@OneToMany
@JoinColumn(name = B.DB_MARKET, referencedColumnName = DB_MARKET, insertable = false, updatable = false)
public List<B> bs;
}
and B class
@Entity
@Table(name = "BTABLE")
public class B implements Serializable {
public static final String DB_ID = "BID";
public static final String DB_MARKET = "BMARKET";
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "id", column = @Column(name = DB_ID)),
@AttributeOverride(name = "market", column = @Column(name = DB_MARKET))
})
public BIdClass id;
}
Each entities might be listed, but using that @OneToMany
relation does throw the following error
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'entityManagerFactory'
Caused by: org.hibernate.AnnotationException: Unable to map collection fr.zzz.domain.A.bs
Caused by: org.hibernate.AnnotationException: referencedColumnNames(AMARKET) of fr.zzz.domain.A.bs referencing fr.zzz.domain.B not mapped to a single property
An A
entity relates to multiple B
on A.AMARKET = B.BMARKET
You are having this issue because there is be a possibility that composite keys (AID,AMARKET) and (BID,BMARKET) will not be unique when doing a join on keys AMARKET = BMARKET. Therefore you are getting the error not mapped to a single property
. Please bear with me, use the following sample data to analyze the issue;
For table A
AID AMARKET
1 1
2 1
3 2
For table B
BID BMARKET
1 1
2 2
3 2
The above scenario is absolutely possible (at least on a database level) and just using AMARKET
and BMARKET
to make the join @OneToMany
is not possible. What is possible though is to use @ManyToMany
, this will immediately solve the issue if the table structures are correct.
But what if it is required to use @OneToMany
due to some business constraint. Then you must update the table B to include A.AID
and add a foreign key constraint to ensure data integrity. Then only the result set will be valid for the relationship @OneToMany
. And the join will be as follows;
@OneToMany
@JoinColumn(name = B.DB_AID, referencedColumnName = DB_ID)
@JoinColumn(name = B.DB_MARKET, referencedColumnName = DB_MARKET)
public List<B> bs;
In B:
@Entity
@Table(name = "BTABLE")
public class B implements Serializable {
public static final String DB_ID = "BID";
public static final String DB_MARKET = "BMARKET";
public static final String DB_AID = "AID";
@EmbeddedId
@AttributeOverrides({
@AttributeOverride(name = "id", column = @Column(name = DB_ID)),
@AttributeOverride(name = "market", column = @Column(name = DB_MARKET))
})
public BIdClass id;
@Column(name = DB_AID)
private Long aid; // assuming aid is a Long
}
Now the join is being done on the composite primary key of A.