nagu
nagu

Reputation: 937

Eclipselink 2.5.1-RC1 JPA 3-Way ManyToMany: Automatic addition/removal of junction table records

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

Answers (1)

Chris
Chris

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

Related Questions