2011-06-16 16 views
62

He escrito con éxito mi primer ejemplo de hijo principal con hibernación. Después de algunos días lo tomé de nuevo y actualicé algunas bibliotecas. No estoy seguro de lo que hice, pero nunca podría hacerlo funcionar nuevamente. ¿Podría alguien ayudar a mi figura lo que está mal en el código que está regresando siguiente mensaje de error: mapeoorg.hibernate.PersistentObjectException: entidad separada pasada para persistir

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) 

de hibernación:

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

factura .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: objeto JSON enviado desde el cliente:

{"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: Algunos detalles:
he tratado de guardar la factura siguiendo dos maneras:

  1. fabricado manualmente mencionado anteriormente objeto json y lo pasó a la sesión de servidor reciente. En este caso absolutamente ninguna actividad se ha realizado antes de llamar método para guardar lo que no debería haber ninguna sesión abierta excepto el que se abrió en Guardar método

  2. cargado los datos existentes mediante el uso de método getInvoice y se las pasó misma datos después de eliminar el valor clave. Esto también creo que debe cerrar la sesión antes de guardar como la transacción se está confirmando en el método getInvoice.

En ambos casos estoy consiguiendo mismo mensaje de error que me está obligando a creer que algo está mal o bien con el archivo de configuración de hibernación o clases de entidad o guardar método.

Por favor, hágamelo saber si debería proporcionar más detalles

Respuesta

82

No proporcionó muchos detalles relevantes, así que supongo que llamó al getInvoice y luego utilizó el objeto de resultado para establecer algunos valores y llamó al save con la suposición de que se guardarán los cambios de su objeto.

Sin embargo, el funcionamiento de persist está destinado a objetos transitorios completamente nuevos y falla si id ya está asignado. En su caso, es probable que desee llamar al saveOrUpdate en lugar de persist.

se pueden encontrar algunos discusión y referencias aquí "detached entity passed to persist error" with JPA/EJB code

+0

Gracias @Alex Gitelman.He agregado algunos detalles en la parte inferior de mi pregunta original. ¿Ayuda entender mi problema? o por favor avíseme qué otros detalles serían útiles. – WSK

+6

su referencia me ayudó a encontrar el error estúpido. Estaba enviando un valor nulo para "itemId" que es la clave principal en la tabla secundaria. Entonces hibernate estaba asumiendo que el objeto ya existe en alguna sesión. Gracias por el consejo – WSK

+0

Ahora recibo este error: "org.hibernate.PropertyValueException: la propiedad no nula hace referencia a un valor nulo o transitorio: example.forms.InvoiceItem.invoice". ¿Podría darme alguna pista? Gracias de antemano – WSK

2

más probable es que el problema se encuentra fuera del código que nos muestran aquí. Está intentando actualizar un objeto que no está asociado con la sesión actual. Si no es la factura, entonces tal vez se trate de un elemento de factura que ya se ha conservado, obtenido de la base de datos, mantenido vivo en algún tipo de sesión y luego intenta persistir en una nueva sesión. Esto no es posible. Como regla general, nunca mantenga vivos sus objetos persistentes en todas las sesiones.

La solución será, por ejemplo, en la obtención del gráfico de objeto completo de la misma sesión con la que intentas persistir.En un entorno web, esto significaría:

  • Obtener la sesión
  • Recuperar los objetos que necesita para actualizar o añadir a las asociaciones. Preferabley por su clave primaria
  • Alter lo que se necesita
  • Guardar/actualizar/evict/borrar lo que quiere
  • Cerrar/commit su sesión/transacción

Si sigue teniendo problemas de publicar algunos de los código que está llamando a su servicio.

+0

Gracias @joostschouten. Aparentemente no debería haber sesión abierta antes de llamar al método guardar como mencioné en "Más detalles" que agregué al final de mi pregunta original. ¿Hay alguna manera de que pueda verificar si existe alguna sesión antes de llamar al método guardar? – WSK

+0

Su suposición "Al parecer, no debe haber sesión abierta antes de llamar al método de guardar" es incorrecta. En su caso, usted está envolviendo una transacción con cada operación de guardado y obtención, lo que significa que las sesiones abiertas no deberían ocurrir y que no servirán. Su problema parece estar en el código que maneja su JSON. Aquí pasa una factura con elementos de factura que ya existen (tienen identificación). Pásalo con identificaciones nulas y lo más probable es que funcione. O haga que su servicio maneje el JSON obtenga los elementos de factura desde el db, agréguelos a la factura y guárdelos en la misma sesión desde la que los obtuvo. – joostschouten

+0

@joostschouten Ahora recibo este error: "org.hibernate.PropertyValueException: propiedad no nula hace referencia a un valor nulo o transitorio: example.forms.InvoiceItem.invoice". ¿Podría darme una idea? Gracias de antemano – WSK

8

Aquí ha utilizado nativa y el valor de la asignación de la clave principal, en la clave primaria nativa se genera automáticamente.

Por lo tanto, el problema está por llegar.

+0

Si cree que tiene información adicional que ofrecer para una pregunta que ya tiene una respuesta aceptada, proporcione una explicación más sustancial. – ChicagoRedSox

Cuestiones relacionadas