Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

org.hibernate.PersistentObjectException: detached entity passed to persist

Tags:

hibernate

I had successfully written my first master child example with hibernate. After few days I took it again and upgraded some libraries. No sure what did I do but I could never make it run again. Would somebody help my figure out what is wrong in code that is returning following error message:

org.hibernate.PersistentObjectException: detached entity passed to persist: example.forms.InvoiceItem     at org.hibernate.event.def.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:127)     at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:799)     at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:791)     .... (truncated) 

hibernate mapping:

<hibernate-mapping package="example.forms">     <class name="Invoice" table="Invoices">         <id name="id" type="long">             <generator class="native" />         </id>         <property name="invDate" type="timestamp" />         <property name="customerId" type="int" />         <set cascade="all" inverse="true" lazy="true" name="items" order-by="id">             <key column="invoiceId" />             <one-to-many class="InvoiceItem" />         </set>     </class>     <class name="InvoiceItem" table="InvoiceItems">         <id column="id" name="itemId" type="long">             <generator class="native" />         </id>         <property name="productId" type="long" />         <property name="packname" type="string" />         <property name="quantity" type="int" />         <property name="price" type="double" />         <many-to-one class="example.forms.Invoice" column="invoiceId" name="invoice" not-null="true" />     </class> </hibernate-mapping> 

EDIT: InvoiceManager.java

class InvoiceManager {      public Long save(Invoice theInvoice) throws RemoteException {         Session session = HbmUtils.getSessionFactory().getCurrentSession();         Transaction tx = null;         Long id = null;         try {             tx = session.beginTransaction();             session.persist(theInvoice);             tx.commit();             id = theInvoice.getId();         } catch (RuntimeException e) {             if (tx != null)                 tx.rollback();             e.printStackTrace();             throw new RemoteException("Invoice could not be saved");         } finally {             if (session.isOpen())                 session.close();         }         return id;     }      public Invoice getInvoice(Long cid) throws RemoteException {         Session session = HbmUtils.getSessionFactory().getCurrentSession();         Transaction tx = null;         Invoice theInvoice = null;         try {             tx = session.beginTransaction();             Query q = session                     .createQuery(                             "from Invoice as invoice " +                             "left join fetch invoice.items as invoiceItems " +                             "where invoice.id = :id ")                     .setReadOnly(true);             q.setParameter("id", cid);             theInvoice = (Invoice) q.uniqueResult();             tx.commit();         } catch (RuntimeException e) {             tx.rollback();         } finally {             if (session.isOpen())                 session.close();         }         return theInvoice;     } } 

Invoice.java

public class Invoice implements java.io.Serializable {      private Long id;     private Date invDate;     private int customerId;     private Set<InvoiceItem> items;      public Long getId() {         return id;     }      public Date getInvDate() {         return invDate;     }      public int getCustomerId() {         return customerId;     }      public Set<InvoiceItem> getItems() {         return items;     }      void setId(Long id) {         this.id = id;     }      void setInvDate(Date invDate) {         this.invDate = invDate;     }      void setCustomerId(int customerId) {         this.customerId = customerId;     }      void setItems(Set<InvoiceItem> items) {         this.items = items;     } } 

InvoiceItem.java

public class InvoiceItem implements java.io.Serializable {      private Long itemId;     private long productId;     private String packname;     private int quantity;     private double price;     private Invoice invoice;      public Long getItemId() {         return itemId;     }      public long getProductId() {         return productId;     }      public String getPackname() {         return packname;     }      public int getQuantity() {         return quantity;     }      public double getPrice() {         return price;     }      public Invoice getInvoice() {         return invoice;     }      void setItemId(Long itemId) {         this.itemId = itemId;     }      void setProductId(long productId) {         this.productId = productId;     }      void setPackname(String packname) {         this.packname = packname;     }      void setQuantity(int quantity) {         this.quantity = quantity;     }      void setPrice(double price) {         this.price = price;     }      void setInvoice(Invoice invoice) {         this.invoice = invoice;     } } 

EDIT: JSON object sent from client:

{"id":null,"customerId":3,"invDate":"2005-06-07T04:00:00.000Z","items":[ {"itemId":1,"productId":1,"quantity":10,"price":100}, {"itemId":2,"productId":2,"quantity":20,"price":200}, {"itemId":3,"productId":3,"quantity":30,"price":300}]} 

EDIT: Some details:
I have tried to save invoice by following two ways:

  1. Manually fabricated above mentioned json object and passed it to fresh session of server. In this case absolutely no activity has been made prior to calling save method so there should not be any open session except the one opened in save method

  2. Loaded existing data by using getInvoice method and them passed same data after removing key value. This too I believe should close the session before saving as transaction is being committed in getInvoice method.

In both cases I am getting same error message that is forcing me to believe that something is wrong either with hibernate configuration file or entity classes or save method.

Please let me know if I should provide more details

like image 875
WSK Avatar asked Jun 16 '11 20:06

WSK


People also ask

How do you resolve a detached entity passed to persist?

The solution is simple, just use the CascadeType. MERGE instead of CascadeType. PERSIST or CascadeType. ALL .

What is the meaning of detached entity passed to persist?

Detached Entities A detached entity is a Java object that is no longer tracked by the persistence context.

How do you persist detached entity in JPA?

saveOrUpdate method, and its cousin Session. update, attach the passed entity to the persistence context while EntityManager. merge method copies the state of the passed object to the persistent entity with the same identifier and then return a reference to that persistent entity.

What is detached entity?

A detached entity is just an ordinary entity POJO whose identity value corresponds to a database row. The difference from a managed entity is that it's not tracked anymore by any persistence context. An entity can become detached when the Session used to load it was closed, or when we call Session.


2 Answers

You didn't provide many relevant details so I will guess that you called getInvoice and then you used result object to set some values and call save with assumption that your object changes will be saved.

However, persist operation is intended for brand new transient objects and it fails if id is already assigned. In your case you probably want to call saveOrUpdate instead of persist.

You can find some discussion and references here "detached entity passed to persist error" with JPA/EJB code

like image 103
Alex Gitelman Avatar answered Sep 21 '22 08:09

Alex Gitelman


This exists in @ManyToOne relation. I solved this issue by just using CascadeType.MERGE instead of CascadeType.PERSIST or CascadeType.ALL. Hope it helps you.

@ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name="updated_by", referencedColumnName = "id") private Admin admin; 

Solution:

@ManyToOne(cascade = CascadeType.MERGE) @JoinColumn(name="updated_by", referencedColumnName = "id") private Admin admin; 
like image 21
Kavitha yadav Avatar answered Sep 20 '22 08:09

Kavitha yadav