2014-09-03 8 views
12

Sto creando una semplice app per inserire semplicemente una riga su una tabella (se la tabella non esiste, crearla) utilizzando Java JPA.org.hibernate.PersistentObjectException: entità separata passata a persist - con JPA

Mi sono guardato su google e qui su SO e ancora non capisco di cosa si tratti. Anche qui ci sono domande con lo stesso problema di me, ma non ho le soluzioni. Sono ancora nuovo con Java JPA, quindi per favore nudo con me.

Allego un codice per un esempio eseguibile.

Torna il problema, ecco l'eccezione sto ottenendo e la stacktrace:

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 

E qui è il mio codice:

Classe principale:

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

e la persona classe:

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() { 
    } 
} 

Ed ecco il mio file 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 ---------- -----------------

Ho appena cambiato il provider in EclipseLink e senza ulteriori modifiche sta funzionando. Sono confuso adesso. Perché funziona con EclipseLink ma con Hibernate genera un'eccezione?

risposta

13

Provare con il codice seguente, quindi consentirà di impostare manualmente lo ID.

Basta usare l'annotazione @Id che consente di definire quale proprietà è l'identificativo della propria entità. Non è necessario utilizzare l'annotazione @GeneratedValue se non si desidera ibernare per generare questa proprietà.

assegnato - consente all'applicazione di assegnare un identificatore all'oggetto prima che venga chiamato save(). Questa è la strategia predefinita se non è specificato l'elemento <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() { 
    } 
} 
12

La ragione di ciò è che si è dichiarato l'id nella classe Person come generato con la strategia automatica che significa JPA tenta di inserire l'id stesso mentre persiste l'entità. Tuttavia nel tuo constructor stai impostando manualmente la variabile id. Poiché l'ID viene assegnato manualmente e l'entità non è presente nello persistence context, ciò causa che JPA pensa che si stia tentando di mantenere un'entità che è separata dal contesto di persistenza e quindi dall'eccezione.

Per risolvere il problema, non impostare l'ID nel costruttore.

@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; 
    } 
+0

E se ho davvero bisogno di impostare l'id sul costruttore? – dazito

+0

In tal caso, non devi dichiararlo come @GeneratedValue con la strategia AUTO –

+0

@dwnz answer postata –

2

Nella definizione di classe si è annotata id da generare dalla strategia (tavolo, di sequenza, ecc), scelto dal provider di persistenza, ma si inizializza l'id dell'oggetto persona attraverso costruttore. Penso che lasciare l'id nullo possa risolvere il tuo problema.

+0

Sì, risolve il mio problema. Ma ha generato un altro problema, cosa succede se ho davvero bisogno di impostare un id sul costruttore di oggetti? – dazito

+0

perché è necessario impostare un ID manualmente? L'ID deve essere assegnato dal provider di persistenza. – Ammaro

+0

Perché mostrerò i dati in un 'JTable' e quindi lo inserirò nel database. E voglio mantenere i dati nel 'JTable' sincronizzati con i dati nella tabella databse. Non voglio andare al database per recuperare tutti i dati (che ho già) solo così posso avere gli ID in 'JTable' aggiornati e non fuori sincrono (id @ JTable! = Id @ DBTable) – dazito

0

È possibile utilizzare questo contrustor come questo:

Person p = new Person(0, "Peter", "Parker"); 

poi quando APP persistono alla base di dati che inseriremo automaticamente con AUTO_INCREMENT strategia.

Problemi correlati