0

I'm getting this error when I build my Application:

Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: model.Student
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:124) [hibernate-core-5.0.7.Final.jar:5.0.7.Final]
    at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:58) [hibernate-core-5.0.7.Final.jar:5.0.7.Final]
    at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:775) [hibernate-core-5.0.7.Final.jar:5.0.7.Final]
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:748) [hibernate-core-5.0.7.Final.jar:5.0.7.Final]
    at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:753) [hibernate-core-5.0.7.Final.jar:5.0.7.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1146) [hibernate-entitymanager-5.0.7.Final.jar:5.0.7.Final]
    ... 190 more

I have to add that, when I use merge(std) instead of persist(std). Than i have no problem which is also weird.

Thats my Entity class with GeneratedValue --> GenerationType.AUTO):

@Entity
@NamedQueries({@NamedQuery(name = Student.QRY_GET_STUDENTS, query = "select s from Student s")})
public class Student {

    public static final String QRY_GET_STUDENTS = "studentQuery";

    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;

    @Size(min = 3, max = 70)
    private String name;

    @Size(min = 7, max = 7, message = "Matrikelnummer muss 7 Ziffern haben!")
    private String matriculationNumber;

    @DecimalMax(value = "5.0", message = "Note muss zwischen 1.0 und 5.0 sein!")
    private double note;

    private String lecture;
}

Thats my persistence class:

@Stateless
@Transactional
public class StudentPersistence {

    @PersistenceContext(unitName = "UniPortalDS")
    private EntityManager em;

    public List<Student> getStudent() {
        return (List<Student>) em.createNamedQuery("studentQuery").getResultList();
    }

public List<Student> saveAllStudentsPersistence(@Nonnull Student std) {
        TypedQuery<Student> q = em.createNamedQuery(std.QRY_GET_STUDENTS, Student.class);
        em.persist(std);
        return q.getResultList();
    }
}

Finally thats my service class:

@Stateless
public class StudentService {

    @EJB
    private StudentPersistence studentPersistence;

    public List<Student> getStudent() {
        return studentPersistence.getStudent();
    }

    //Jetzt -->
    public void saveStudentsNew(@Nonnull Student std) {
        studentPersistence.saveAllStudentsPersistence(std);
    }
}
Matteo Baldi
  • 5,613
  • 10
  • 39
  • 51

1 Answers1

1

In JPA, "non-persistent" and "detached" are not the same thing:

  • non-persistent: these entities do not currently exist in the DB. You can take a non-persistent entity, invoke persist() on it, and that should make it persistent (that is, store it in the DB).

  • detached: these entities do exist in the DB, but are not currently being managed be the EntityManager. It makes no sense to persist() them because although they are currently detached they are already persistent, and I think this is the error that Hibernate is communicating to you. However, you can merge() them, that is, synchronize them with the persistence context and turning them into entities managed by the EntityManager so that changes are sent to the DB (1).

(1) Actually, merge() does not transition the entity from detached to managed; what it does is take some entity in whatever state it is, and return a corresponding managed instance. The original instance remains in whatever state it was.

gpeche
  • 21,974
  • 5
  • 38
  • 51
  • 2
    Just a small precision (because I've seen that error done often); when people get "detached entity passed to persist", it means JPA **guessed** it might already be in the DB, but it's not in its persistence context. It's done by just checking if the @Id field is set or not and if that Id is in its persistence context, so ANY object you try to persist, if the Id field is set, will throw that exception. In the OP's case, if anyone calls saveStudentsNew with an Id already set, it will do that. – Simon Berthiaume Mar 09 '18 at 12:29
  • If the instance is not persistent it should accept it no matter whether the id has been set or not, not all ids are autogenerated. Or am i missing something? – gpeche Mar 09 '18 at 12:42
  • It's been a while since I seriously played with JPA (2-3 years), but I think you have a point, just having an \@Id field set won't systematically fail **BUT** if that \@Id field also has \@GeneratedValue it will (or at least used to). – Simon Berthiaume Mar 09 '18 at 13:03
  • @SimonBerthiaume That is the correct answer! persist can fail when there is an ID set (used primitive long which caused it to be 0 instead of null) – elad.chen May 22 '20 at 10:53