Jordan Allan
Jordan Allan

Reputation: 4486

JPA update many-to-many deleting records

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;

    ...
} 

Upvotes: 3

Views: 13003

Answers (4)

Bian Jiaping
Bian Jiaping

Reputation: 966

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.

Upvotes: 3

Jordan Allan
Jordan Allan

Reputation: 4486

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

Upvotes: 0

Igor Mukhin
Igor Mukhin

Reputation: 15368

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(...);

Upvotes: 2

Jherico
Jherico

Reputation: 29240

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.

Upvotes: 1

Related Questions