1

Copy & paste some introductory part from my previous question.

I'm using JPA 2.0 in EclipseLink 2.3.2 in which I have a many-to-many relationship between products and their colours. A product can have many colours and a colour can be associated with many products. This relationship is expressed in the database by three tables.

  • product
  • prod_colour (join table)
  • colour

The prod_colour table has two reference columns prod_id and colour_id from its related parent tables product and colour respectively.

As obvious, the entity class Product has a set of colours - java.util.Set<Colour> which is named colourSet.

The entity class Colour has a set of products - java.util.Set<Product> which is named productSet.


To add and delete rows to and from the prod_colour table, I have defined two methods in the Colour entity class itself as follows.

public void addToProduct(Product product) {
    this.getProductSet().add(product);
    product.getColourSet().add(this);
}

public void removeFromProduct(Product product) {
    this.getProductSet().remove(product);
    product.getColourSet().remove(this);
}

These methods are called from an EJB as follows.

@Override
@SuppressWarnings("unchecked")
public void insert(List<Colour> colours, Product product) {
    for (Colour colour : colours) {
        colour.addToProduct(product);
    }
}

@Override
@SuppressWarnings("unchecked")
public void delete(Colour colour, Product product) {
    colour.removeFromProduct(product);
}

I expect them to add and delete rows to and from the prod_colour table but nothing happens (no error, no exception is caused). The same thing works in Hibernate. So, what else is missing here?


EDIT:

The Product entity class:

public class Product implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "prod_id")
    private Long prodId;

    private static final long serialVersionUID = 1L;

    @JoinTable(name = "prod_colour", joinColumns = {
        @JoinColumn(name = "prod_id",
                    referencedColumnName = "prod_id")},
                    inverseJoinColumns = {
                        @JoinColumn(name = "colour_id", referencedColumnName = "colour_id")})
    @ManyToMany(fetch = FetchType.LAZY)
    private Set<Colour> colourSet;

    //Getters and Setters.
}

The Colour entity class.

public class Colour implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "colour_id")
    private Long colourId;

    private static final long serialVersionUID = 1L;

    @ManyToMany(mappedBy = "colourSet", fetch = FetchType.LAZY)

    private Set<Product> productSet;

    //Setters and getters.
}
Community
  • 1
  • 1
Tiny
  • 27,221
  • 105
  • 339
  • 599
  • Yes both of them don't work (no error, no exception is caused). – Tiny Nov 08 '13 at 23:07
  • Are you sure, you check the right table? Have you checked the DB query log? Do you do also a merge with `entityManager.merge(colour)` eventually also with the product? – V G Nov 08 '13 at 23:09
  • Yes this doesn't generate any `DELETE` or `INSERT` statement (I have enabled debugging in the `presistence.xml` file). – Tiny Nov 08 '13 at 23:12
  • What about the merge/save of the entities in DB with `entityManager.merge(colour)`? – V G Nov 08 '13 at 23:13
  • With `entityManager.merge(colour)`, changes are saved to the `colour` table itself which should be made to the `prod_colour` table - join table. – Tiny Nov 08 '13 at 23:19
  • :) well, I think it is time for you to show me your entities, to see how they are mapped, but you MUST definitely save either the colour, or product. Saving the colour, almost sure means saving in both tables. – V G Nov 08 '13 at 23:23
  • Edited to include the entity classes. – Tiny Nov 08 '13 at 23:33
  • OK, in order to update that join table, you need e.g fully/eagerly loaded entities and after you code, do not forget to call the entityManager.merge(colour); & entityManager.merge(product); Also I think you need a book or some good tutorials in order to understand how ManyTo* relationships & the fetchtype works. – V G Nov 08 '13 at 23:35
  • With these changes, both the operations `INSERT` (`FetchType.EAGER`, `entityManager.merge(colour);entityManager.merge(product);`) and `DELETE` (don't require `entityManager.remove(colour);entityManager.remove(product);`) now work as they should. May put this as an answer. Thank you very much. – Tiny Nov 08 '13 at 23:54

1 Answers1

1

In order to update that join table, you need e.g fully/eagerly loaded entities and after you code, do not forget to call:

entityManager.merge(colour);
entityManager.merge(product);
Tiny
  • 27,221
  • 105
  • 339
  • 599
V G
  • 18,822
  • 6
  • 51
  • 89
  • 1
    Like Hibernate, lazy fetch in a many-to-many relationship also works for updating (and all other) operations in [EclipseLink 2.5.1](http://www.eclipse.org/downloads/download.php?file=/rt/eclipselink/releases/2.5.1/eclipselink-2.5.1.v20130918-f2b9fc5.zip). Not quite enough sure about the version, in addition to updating EclipseLink, I have also changed `java.util.Set` to `java.util.List` everywhere in the application and made a few other changes. These changes may be a discrepancy. It happened almost all accidently and I could not find the exact reason how and when lazy fetch started working. – Tiny Apr 28 '14 at 01:47