Reputation: 937
I have 3 entities: X, Y, Z. An X is made of collection of Ys associating each Y with a Z. (Y-Z) -> X association is maintained in a junction/link table called YZ_2_X_Map with three references as a composite primary key: YId, ZId, XId.
Following is the code for X entity:
@Entity
public class X implements Serializable {
// Properties
//bi-directional many-to-one association to YZ_2_X_Map
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="x")
@JoinTable(name="YZ_2_X_Map",
joinColumns=
@JoinColumn(name="XId")
)
private List<YZ_2_X_Map> yZList;
public void setYZList(List<YZ_2_X_Map> yZList) {
this.yZList = yZList;
}
}
Following is the code for YZ_2_X_Map entity:
public class YZ_2_X_Map implements Serializable {
private static final long serialVersionUID = 1L;
@EmbeddedId
private YZ_2_X_MapPK id;
//bi-directional many-to-one association to Y
@ManyToOne
@JoinColumn(name="YId")
private Y y;
//bi-directional many-to-one association to Z
@ManyToOne
@JoinColumn(name="ZId")
private Z z;
//bi-directional many-to-one association to X
@ManyToOne
@JoinColumn(name="XId")
private X x;
// Methods
}
My expectation is that whenever I persist X, based on entries in yZList, records in YZ_2_X_Map junction table should be inserted/deleted.
With the code above, adding new entries to yzList adds new records in YZ_2_X_Map table as per my expectation.
However, removing entries from yzList does not remove the corresponding records from YZ_2_X_Map table.
I also tried removing mappedBy from @OneToMany annotation in class X and removing x property from class YZ_2_X_Map. In this case, while removing entries from yzList removes corresponding records, adding new entries to yzList and persisting X generates INSERT into YZ_2_X_Map but throws duplicate-entry exception.
Please let me know how I can achieve my expectation of automatic addition/removal of records in YZ_2_X_Map table based on entries in yZList.
Upvotes: 1
Views: 233
Reputation: 21165
You created an entity for the YZ_2_X_Map table, but then are creating a 1:m Mapping to that entity that is using a YZ_2_X_Map join table - effectively a join table to a join table. The mappedBy="x" tells the mapping that the foreign key to use is contained in the YZ_2_X_Map.x mapping. A Join table or join column is only required if this was the owning side of the relationship, or if it was unidirectional.
all that is needed is:
public class X implements Serializable {
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="x")
private List<YZ_2_X_Map> yZList;
...
If you want JPA to operate such that removing an Entity from the yZList causes the YZ_2_X_Map entity and the row to be deleted, then you will need to mark the relationship as either privately owned (EclipseLink specific) or if using JPA 2.0, with orphanRemoval=true. This will force JPA to delete the entity as well when it is dereferenced from the mapping.
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, orphanRemoval=true, mappedBy="x")
or
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="x")
@PrivateOwned
private List<YZ_2_X_Map> yZList;
Upvotes: 2