J'avais réussi à écrire mon premier exemple de maître enfant avec hibernate. Après quelques jours, je l'ai repris et mis à niveau certaines bibliothèques. Je ne sais pas ce que j'ai fait mais je ne pourrais plus jamais le faire fonctionner. Quelqu'un pourrait-il m'aider à comprendre ce qui ne va pas dans le code qui renvoie le message d'erreur suivant:
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)
mappage d'hibernation:
<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>
MODIFIER: 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;
}
}
Facture.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:
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
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
Invoice
first, so it will get id and then saveInvoiceItem
. You may also play with cascading.Here you have used native and assigning value to the primary key, in native primary key is auto generated.
Hence the issue is coming.
la source
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;
la source
Most likely the problem lies outside the code you are showing us here. You are trying to update an object that is not associated with the current session. If it is not the Invoice, then maybe it is an InvoiceItem that has already been persisted, obtained from the db, kept alive in some sort of session and then you try to persist it on a new session. This is not possible. As a general rule, never keep your persisted objects alive across sessions.
The solution will ie in obtaining the whole object graph from the same session you are trying to persist it with. In a web environment this would mean:
If you keep having issues post some of the code that is calling your service.
la source
Two solutions 1. use merge if you want to update the object 2. use save if you want to just save new object (make sure identity is null to let hibernate or database generate it) 3. if you are using mapping like
@OneToOne(fetch = FetchType.EAGER,cascade=CascadeType.ALL) @JoinColumn(name = "stock_id")
Then use CascadeType.ALL to CascadeType.MERGE
thanks Shahid Abbasi
la source
For JPA fixed using EntityManager merge() instead of persist()
EntityManager em = getEntityManager(); try { em.getTransaction().begin(); em.merge(fieldValue); em.getTransaction().commit(); } catch (Exception e) { //do smthng } finally { em.close(); }
la source
I had the "same" problem because I was writting
@GeneratedValue(strategy = GenerationType.IDENTITY)
I deleted that line due that I do not need it at the moment, I was testing with objects and so. I think it is
<generator class="native" />
in your caseI do not have any controller and my API is not being accessed, it is only for testing (at the moment).
la source