3

I have a @ManyToMany relationship between two entities. When I perform an update on the owning side, it appears that JPA deletes all the linked records from my database and re-inserts them. For me this is a problem because I have a MySQL trigger that fires before a record is deleted. Any ideas on how to get around this problem?

@Entity
public class User {

    @Id
    @Column(name="username")
    private String username;

    ...

    @ManyToMany
    @JoinTable(name="groups", joinColumns=
        @JoinColumn(name="username", referencedColumnName="username"),
            inverseJoinColumns=@JoinColumn(name="groupname",
                    referencedColumnName="type_id"))
    private List<UserType> types;

    ...

}

@Entity
public class UserType {

    @Id
    @Column(name="type_id")
    private String id;

    @ManyToMany(mappedBy="types")
    private List<User> users;

    ...
} 
Jordan Allan
  • 4,408
  • 7
  • 32
  • 35

4 Answers4

3

Use Set instead of List solved the problem. But I have no idea why it works.

Another solution provided by Hibernate is to split the @ManyToMany association into two bidirectional @OneTo@Many relationships. See Hibernate 5.2 documentation for example.

If a bidirectional @OneToMany association performs better when removing or changing the order of child elements, the @ManyToMany relationship cannot benefit from such an optimization because the foreign key side is not in control. To overcome this limitation, the link table must be directly exposed and the @ManyToMany association split into two bidirectional @OneToMany relationships.

Bian Jiaping
  • 946
  • 8
  • 20
2

Try this one:

1) change declaration to:

private List<UserType> types = new Vector<UserType>();

2) never call

user.setTypes(newTypesList)

3) only call

user.getTypes().add(...);
user.getTypes().remove(...);
Igor Mukhin
  • 15,014
  • 18
  • 52
  • 61
1

Its probably related to this question. You have to ensure you have an appropriately defined hashCode an equals method in your mapped object so that Eclipselink can determine equality and thus determine that the existing objects map to existing objects in the DB. Otherwise it has no choice but to recreate the child objects every time.

Alternatively, I've read that this kind of join can only support efficient adding and removing of list items if you use an index column, but that's going to be EclipseLink specific, since the JPA annotations don't seem to support such a thing. I know there is an equivalent Hibernate annotation, but I don't know what it would be in Eclipselink, if such a thing exists.

Community
  • 1
  • 1
Jherico
  • 28,584
  • 8
  • 61
  • 87
  • Thanks for the insight. I tried overriding the equals and hashCode methods in my User class; however it still doesn't prevent JPA from removing/recreating the records in my join table. Perhaps I am not implementing this correctly... – Jordan Allan Aug 17 '10 at 19:17
  • JPA doesn't use object identity but database identity. – Pascal Thivent Aug 18 '10 at 08:06
0

It appears my problem was that I was not merging the entity.

Jordan Allan
  • 4,408
  • 7
  • 32
  • 35