Org.hibernate.PersistentObjectException: удаленный объект передается для сохранения - с JPA
Я создаю простое приложение, чтобы просто вставить строку в таблицу (если таблица не существует, создайте ее) с помощью Java JPA
.
Я посмотрел на google и здесь на SO, и я до сих пор не понимаю, что это за исключение. Даже здесь есть вопросы с той же проблемой, что и у меня, но я не получаю решения. Я все еще новичок в Java JPA
, поэтому, пожалуйста, со мной.
Я прикрепляю некоторый код для запускаемого примера.
Вернуться к проблеме, здесь исключение, которое я получаю, и стек:
EXCEPTION -- > org.hibernate.PersistentObjectException: detached entity passed to persist: view.Person
javax.persistence.PersistenceException: org.hibernate.PersistentObjectException: detached entity passed to persist: view.Person
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1763)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1677)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1683)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1187)
at view.TestJPA.main(TestJPA.java:34)
Caused by: org.hibernate.PersistentObjectException: detached entity passed to persist: view.Person
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:139)
at org.hibernate.event.internal.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:75)
at org.hibernate.internal.SessionImpl.firePersist(SessionImpl.java:811)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:784)
at org.hibernate.internal.SessionImpl.persist(SessionImpl.java:789)
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:1181)
... 1 more
И вот мой код:
Основной класс:
package view;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class TestJPA {
public static void main(String[] args) {
Person p = new Person(1, "Peter", "Parker");
EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("TesePersistentUnit");
EntityManager entityManager = entityManagerFactory.createEntityManager();
EntityTransaction transaction = entityManager.getTransaction();
try {
transaction.begin();
entityManager.persist(p);
entityManager.getTransaction().commit();
}
catch (Exception e) {
if (transaction != null) {
transaction.rollback();
}
System.out.println("EXCEPTION -- > " + e.getMessage());
e.printStackTrace();
}
finally {
if (entityManager != null) {
entityManager.close();
}
}
}
}
И класс Person:
package view;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "People")
public class Person {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
private String name;
private String lastName;
public Person(int id, String name, String lastName) {
this.id = id;
this.name = name;
this.lastName = lastName;
}
public Person() {
}
}
И вот мой файл persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="TesePersistentUnit" transaction-type="RESOURCE_LOCAL">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<class>view.Person</class>
<properties>
<!-- SQL dialect -->
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/tese_tabelas?zeroDateTimeBehavior=convertToNull"/>
<property name="javax.persistence.jdbc.user" value="root"/>
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
<property name="javax.persistence.jdbc.password" value=""/>
<!-- Create/update tables automatically using mapping metadata -->
<property name="hibernate.hbm2ddl.auto" value="update"/>
</properties>
</persistence-unit>
</persistence>
----------------------- EDIT -------------------- -------
Я только что изменил провайдера на EclipseLink и никаких дальнейших изменений он не работает. Теперь я смущен. Почему это работает с EclipseLink, но с Hibernate генерирует исключение?
Ответы
Ответ 1
Попробуйте с приведенным ниже кодом, это позволит вам установить ID
вручную.
Просто используйте аннотацию @Id
, которая позволяет определить, какое свойство является идентификатором вашего объекта. Вам не нужно использовать аннотацию @GeneratedValue
, если вы не хотите, чтобы спящий режим сгенерировал это свойство для вас.
назначено - позволяет приложению назначать идентификатор объекту до вызова save()
. Это стратегия по умолчанию, если не указан элемент <generator>
.
package view;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "People")
public class Person {
@Id
//@GeneratedValue(strategy = GenerationType.AUTO) // commented for manually set the id
private int id;
private String name;
private String lastName;
public Person(int id, String name, String lastName) {
this.id = id;
this.name = name;
this.lastName = lastName;
}
public Person() {
}
}
Ответ 2
Причиной этого является то, что вы объявили идентификатор в классе Person
, сгенерированный с помощью автоматической стратегии, смысл JPA
пытается вставить сам идентификатор, сохраняя объект. Однако в вашем constructor
вы вручную устанавливаете переменную id. Поскольку идентификатор назначается вручную и что объект не присутствует в persistence context
, это приводит к тому, что JPA
полагает, что вы пытаетесь сохранить сущность, которая отделена от контекста персистентности и, следовательно, исключение.
Чтобы исправить это, не устанавливайте идентификатор в конструкторе.
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private int id;
public Person(int id, String name, String lastName) {
// this.id = id;
this.name = name;
this.lastName = lastName;
}
Ответ 3
В определении класса у вас есть аннотированный идентификатор, который должен быть сгенерирован стратегией (таблица, последовательность и т.д.), выбранный поставщиком сохранения, но вы инициализируете идентификатор объекта Person через конструктор. Я думаю, что оставить id null может решить вашу проблему.
Ответ 4
Вы можете использовать этот contrustor следующим образом:
Person p = new Person(0, "Peter", "Parker");
тогда, когда JPA сохраняется в базе данных, она автоматически добавит стратегию AUTO_INCREMENT
.