Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring + JPA many to many relationship

I'm very new to Spring and I'm trying to make a many-to-many relationship work as I expect. The relationships works fine, the tables are created and the data is inserted correctly. What I expect, is that when I empty a List (i.e. I empty the ArrayList "users" from an object of type "Group"), I expect the system to remove the relationships from the database - but it doesn't.

I have the following classes:

@Entity
@Table(name = "`group`")
public class Group
{
    @Id
    @GeneratedValue
    @Column(name = "id")
    private int id;

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

    @ManyToMany(cascade = {CascadeType.ALL})
    @JoinTable(
            name = "`user_has_group`",
            joinColumns = @JoinColumn(name = "group_id", referencedColumnName = "id"),
            inverseJoinColumns = @JoinColumn(name = "user_id", referencedColumnName = "id")
    )
    private List<User> users = new ArrayList<User>();

    ...
}

@Entity
@Table(name = "`user`")
public class User
{
    @Id
    @GeneratedValue
    @Column(name = "id")
    private int id;

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

    @ManyToMany(mappedBy = "users")
    private List<Group> groups = new ArrayList<Group>();

    ...
}

Here are the DAOs:

@Repository
public class GroupJpaDao implements GroupDao
{
    private EntityManager em;

    @Transactional
    public void save(Group group)
    {
        this.em.merge(group);
    }

    ...

    @PersistenceContext
    void setEntityManager(EntityManager entityManager)
    {
        this.em = entityManager;
    }
}

@Repository
public class UserJpaDao implements UserDao
{
    private EntityManager em;

    @Transactional
    public void save(User user)
    {
        this.em.merge(user);
    }

    ...

    @PersistenceContext
    void setEntityManager(EntityManager entityManager)
    {
        this.em = entityManager;
    }
}

Here is the test method:

@Test
public void test()
{
    Group g = new Group();
    g.setName("Test group");
    groupDao.save(g); // Works fine - inserts the group into the database

    User u = new User();
    u.setName("Test user");
    userDao.save(u); // Works fine - inserts the user into the database

    g.addUser(u);
    groupDao.save(g); // Works fine - adds the many-to-many relationship into the database

    g.removeAllUsers();
    groupDao.save(g); // Doesn't work - I'm expecting it to remove all the related relationships from the database but it doesn't!
}

Am I doing something wrong or is it something not possible to do?

Any hint is really appreciated.

Thank you!

like image 487
satoshi Avatar asked Jan 12 '12 17:01

satoshi


People also ask

How do you define many-to-many relationship using JPA?

In JPA we use the @ManyToMany annotation to model many-to-many relationships. This type of relationship can be unidirectional or bidirectional: In a unidirectional relationship only one entity in the relationship points the other. In a bidirectional relationship both entities point to each other.

How do you create a many-to-many relationship in spring boot JPA?

In JPA, we use the @ManyToMany annotation to model Many to Many Relationships. It could either be Uni-directional or Bi-directional. In a unidirectional association, only one entity points to another. In a bidirectional association, both the entities point to each other.

What is many-to-many relationship in hibernate?

Hibernate. Hibernate Mapping. Learn to create and manage many-to-many relationships between entities in a hibernate/JPA-based applications using @ManyToMany annotation. A many-to-many association is made between two entities where one entity can be associated with multiple other instances of the other entity.


1 Answers

I reread your question, and now the answer is clear. Your create a Group g, and save it. But since your save method uses merge, and you don't take into account the value returned by merge to assign it to g, you keep merging the transient group g, which never has any ID assigned. So, each time merge is called, you actually create a new group rather than modifying the previously created one.

Change the save method to

public Group save(Group group)
{
    return this.em.merge(group);
}

and always reassign the result to g:

g = groupDao.save(g);

Of course, the same must be done for the user.

like image 55
JB Nizet Avatar answered Sep 18 '22 11:09

JB Nizet