Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
Re: [eclipselink-users] ManyToMany did not persist in both directions

Hello,

From the sounds of it, you have a bi-directional M:M, and are only populating one of the collection types. When the one that is populated is the side that owns the relationship, you get the join table inserts as expected. When the other collection is populated, and the collection that owns the relationship is left blank, you don't. This is as designed.

The specification requires both sides to be maintained. So if the application is populating one side of the relationship, it should (must) populate the other side to keep it consistent with what will (or is desired to) be in the database. When they are inconsistent, you get inconsistent results. In this case, the state of the two collections do not match, and the one that owns the relationship is taken to represent the actual values for the database. Allowing changes to both sides to be reflected into the database would lead to potential duplicate results - for instance when an application correctly maintains both sides of the relationship, an entry to the join table might get duplicated. It is also then impossible to tell what should happen when a reference is removed from one collection but left in the other.

Best Regards,
Chris

farisola@xxxxxx wrote:
Hello, using annotation @ManyToMany did not persist in both directions:

I have to n:m related tables, LEHRER and SCHUELER

That results in 3 database tables:

1. LEHERER
2. SCHUELER
3. LEHERER_SCHUELER

At the end you can find the two corresponding entity classes
and the two test cases.

Both entites contain the neccessary @ManyToMany annotations, see below.
The entity LEHERER contains the @JoinTable annotation, the entity SCHUELER not.

The problem:
If I persist a new LEHRER entity that contains some SCHUELER,
then all three tables will have the corresponding entries.

But if I persist a new SCHUELER entity that contains some LEHRER ,
then ONLY the tables SCHUELER and LEHRER will have the corresponding entries,
but the table LEHERER_SCHUELER will be ignored.
<<<

I think the persistence should work in both directions independent of the place,
where the @JoinTable annotation is placed.

All is running on a Oracle 10g Database.

Did someone have an idea, what is wrong?

// +-----------------------------------------------------------------------+
@Entity
@Table(name="LEHRER")
public class Lehrer extends ZAdminEntity implements Serializable {
  private static final long serialVersionUID = 1L;
  private long pk;
  private String lehrername;
  private List<Schueler> schuelers;

  public Lehrer() { }

  @Id
  @SequenceGenerator(name="LEHRER_PK_GENERATOR", sequenceName="SEQ_LEHRER")
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="LEHRER_PK_GENERATOR")
  @Column(unique=true, nullable=false, precision=22)
  public long getPk() {
    return this.pk;
  }

  public void setPk(long pk) {
    this.pk = pk;
  }

  @Column(nullable=false)
  public String getLehrername() {
    return this.lehrername;
  }

  public void setLehrername(String lehrername) {
    this.lehrername = lehrername;
  }

  //bi-directional many-to-many association to Schueler
  @ManyToMany(cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
  @JoinTable(
    name="LEHRER_SCHUELER"
      , joinColumns={@JoinColumn(name="LEHRER_PK", nullable=false)}
      , inverseJoinColumns={@JoinColumn(name="SCHUELER_PK", nullable=false)}
    )
  public List<Schueler> getSchuelers() {
    return this.schuelers;
  }

  public void setSchuelers(List<Schueler> schuelers) {
    this.schuelers = schuelers;
  }
}

// +-----------------------------------------------------------------------+
@Entity
@Table(name="SCHUELER")
public class Schueler extends ZAdminEntity implements Serializable {
  private static final long serialVersionUID = 1L;
  private long pk;
  private String schuelername;
  private List<Lehrer> lehrers;

  public Schueler() {}

  @Id
  @SequenceGenerator(name="SCHUELER_PK_GENERATOR", sequenceName="SEQ_SCHUELER")
  @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SCHUELER_PK_GENERATOR")
  @Column(unique=true, nullable=false, precision=22)
  public long getPk() {
    return this.pk;
  }

  public void setPk(long pk) {
    this.pk = pk;
  }

  @Column(nullable=false)
  public String getSchuelername() {
    return this.schuelername;
  }

  public void setSchuelername(String schuelername) {
    this.schuelername = schuelername;
  }

  //bi-directional many-to-many association to Lehrer
  @ManyToMany(mappedBy="schuelers", cascade={CascadeType.ALL}, fetch=FetchType.EAGER)
  public List<Lehrer> getLehrers() {
    return this.lehrers;
  }

  public void setLehrers(List<Lehrer> lehrers) {
    this.lehrers = lehrers;
  }

}
// +-----------------------------------------------------------------------+
  @Test
  /**
   * Is working!
   */
  public void lehrerschueler() {
    EntityManagerFactory emf = getEMF();
    EntityManager em = emf.createEntityManager();
    Lehrer lehrer = this.getNewLehrer();
    Schueler schueler = this.getNewSchueler();
    ArrayList  <Schueler> list = new ArrayList <Schueler> ();
    list.add(schueler);
    lehrer.setSchuelers(list);
    em.getTransaction().begin();
    try {
      // persist the lehrer
      em.persist(lehrer);
      em.getTransaction().commit();
    } catch (Exception e) {
      e.printStackTrace();
      Assert.fail(e.getMessage());
    }
  }
// +-----------------------------------------------------------------------+

  @Test
  /**
   * IS NOT working!
   */
  public void schuelerlehrer() {
    EntityManagerFactory emf = getEMF();
    EntityManager em = emf.createEntityManager();
    Schueler schueler = this.getNewSchueler();
    Lehrer lehrer = this.getNewLehrer();
    ArrayList <Lehrer> list = new ArrayList <Lehrer> ();
    list.add(lehrer);
    schueler.setLehrers(list);
    em.getTransaction().begin();
    try {
      // persist the schueler
      em.persist(schueler);
      em.getTransaction().commit();
    } catch (Exception e) {
      e.printStackTrace();
      Assert.fail(e.getMessage());
    }
  }
// +-----------------------------------------------------------------------+

greetings Farisola



Back to the top