I have this entity model (simplified):
@Entity
class A {
@Id
String id;
Collection<B> bs;
}
@Entity
class B {
@Id
String id;
@ManyToOne
@JoinColumn(name = "c_id", nullable = false)
C c;
}
@Entity
class C {
@Id
String id;
}
What would be the best approach to add a join table between A and B (many-to-many relation) and enforce a composite UK using A.id and B.c.id?
I tried something like this:
@ManyToMany(cascade = CascadeType.ALL)
@JoinTable
(name = "a_b",
joinColumns = @JoinColumn(name = "a_id"),
inverseJoinColumns = {
@JoinColumn(name = "b_id", referencedColumnName = "id"),
@JoinColumn(name = "c_id", referencedColumnName = "c_id")},
uniqueConstraints = @UniqueConstraint(name = "uk_a_c", columnNames = {"a_id", "c_id"}))
but I get a MultipleBagFetchException
, which is very strange. It must be related to the fact that c_id
is not part of the primary key. If I remove c_id
from inverseJoinColumns
it works as expected, but it's not what I need.
My final mapping looks like this:
@Entity
@EntityListeners(ABListener.class)
@Table(name = "a_b", uniqueConstraints =
@UniqueConstraint(name = "uk_rel_a_b", columnNames = {"a_id", "c_id"}))
public class AB extends BaseEntity<Long> {
private Long id;
@ManyToOne(optional = false)
@JoinColumn(name = "a_id")
private A a;
@ManyToOne(optional = false)
@JoinColumn(name = "b_id")
private B b;
@ManyToOne(optional = false)
@JoinColumn(name = "c_id")
private C c;
public AB(A a, B b) {
this.a = a;
this.b = b;
}
/* rest of the class */
}
And a listener to handle setting of C
:
public class ABListener {
@PrePersist
@PreUpdate
void handleCUpdate(AB ab) {
if (ab.getB() != null) {
ab.setC(ab.getB().getC());
}
}
}