0

I am trying to understand the principles of ManyToMany relations in Hibernate. I've created a small test project and the question is: I want "Managers" to be saving in db when the "User" is saving. So Manager entity is dependent on User. When I am saving user1 - everything is fine. I am getting user1 and manager1 and manager3 saved to db. But on the next row where I am trying to save user2 to db I am getting an Exception: Converting org.hibernate.PersistentObjectException to JPA PersistenceException : detached entity passed to persist: ua.testing.entities.Manager

I think the problem is because I am trying to save user2 which contains manager1, which was saved in db in previous row. But how can I avoid this problem and make everything work?

User entity:

    package ua.testing.entities;
    
    import jakarta.persistence.*;
    
    import java.util.ArrayList;
    import java.util.List;
    
    @Entity
    @Table(name = "user")
    public class User {
        @Id
        @GeneratedValue(strategy = GenerationType.IDENTITY)
        private Long id;
        @ManyToMany(cascade = CascadeType.ALL)
        private List<Manager> managerList = new ArrayList<>();
    
        public Long getId() {
            return id;
        }
    
        public void setId(Long id) {
            this.id = id;
        }
    
        public List<Manager> getManagerList() {
            return managerList;
        }
    
        public void setManagerList(List<Manager> managerList) {
            this.managerList = managerList;
        }
    }

Manager entity:

package ua.testing.entities;

import jakarta.persistence.*;

import java.util.ArrayList;
import java.util.List;

@Entity
@Table(name = "manager")
public class Manager {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @ManyToMany(mappedBy = "managerList")
    private List<User> userList = new ArrayList<>();

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public List<User> getUserList() {
        return userList;
    }

    public void setUserList(List<User> userList) {
        this.userList = userList;
    }
}

Main method:

package ua.testing;

import ua.testing.dao.UserDao;
import ua.testing.entities.*;

public class App 
{
    public static void main( String[] args )
    {
        User user1 = new User();
        User user2 = new User();
        User user3 = new User();

        Manager manager1 = new Manager();
        Manager manager2 = new Manager();
        Manager manager3 = new Manager();

        manager1.getUserList().add(user1);
        manager1.getUserList().add(user2);
        manager2.getUserList().add(user1);
        manager2.getUserList().add(user3);
        manager3.getUserList().add(user2);
        manager3.getUserList().add(user3);

        user1.getManagerList().add(manager1);
        user1.getManagerList().add(manager3);
        user2.getManagerList().add(manager1);
        user2.getManagerList().add(manager2);
        user3.getManagerList().add(manager2);
        user3.getManagerList().add(manager3);

        UserDao userDao = new UserDao();
        userDao.persist(user1);
        userDao.persist(user2);  // EXCEPTION HERE

    }

}

Exception I am getting:

Exception in thread "main" jakarta.persistence.PersistenceException: Converting `org.hibernate.PersistentObjectException` to JPA `PersistenceException` : detached entity passed to persist: ua.testing.entities.Manager
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:165)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:175)
    at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:182)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:783)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:725)
    at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:299)
    at org.hibernate.engine.spi.CascadingActions$7.cascade(CascadingActions.java:289)
    at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:511)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:432)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:218)
    at org.hibernate.engine.internal.Cascade.cascadeCollectionElements(Cascade.java:545)
    at org.hibernate.engine.internal.Cascade.cascadeCollection(Cascade.java:475)
    at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:435)
    at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:218)
    at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:151)
    at org.hibernate.event.internal.AbstractSaveEventListener.cascadeAfterSave(AbstractSaveEventListener.java:474)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
    at org.hibernate.event.internal.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:192)
    at org.hibernate.event.internal.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:122)
    at org.hibernate.event.internal.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:184)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:129)
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:53)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:107)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:735)
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:719)
    at ua.testing.dao.UserDao.persist(UserDao.java:13)
    at ua.testing.App.main(App.java:34)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: ua.testing.entities.Manager
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:121)
    at org.hibernate.event.service.internal.EventListenerGroupImpl.fireEventOnEachListener(EventListenerGroupImpl.java:118)
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:777)
    ... 23 more
  • Is your userDao.persist method by chance performing a 'save' operation under the covers? Make sure it really is a em.persist under the covers. You might not want to create the full model and all references before calling persist though - your user1 object graph references everything (Manager1 and 2, which references Users2 and 3, which reference manager3). So if you set your cascade options, you don't need the second persist call at all. You should not be setting any references to user2/3 until after you persisted user1 in this code. – Chris Dec 07 '22 at 23:21

0 Answers0