Ich hatte mein erstes Masterkind-Beispiel mit Ruhezustand erfolgreich geschrieben. Nach ein paar Tagen nahm ich es wieder und aktualisierte einige Bibliotheken. Ich bin mir nicht sicher, was ich getan habe, aber ich konnte es nie wieder zum Laufen bringen. Würde mir jemand helfen, herauszufinden, was im Code falsch ist, der die folgende Fehlermeldung zurückgibt:
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)
Zuordnung im Ruhezustand:
<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>
BEARBEITEN : 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;
}
}
BEARBEITEN: Vom Client gesendetes JSON-Objekt:
{"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}]}
BEARBEITEN: Einige Details:
Ich habe versucht, die Rechnung auf zwei Arten zu speichern:
Das oben erwähnte JSON-Objekt wurde manuell hergestellt und an eine neue Serversitzung übergeben. In diesem Fall wurde vor dem Aufrufen der Speichermethode absolut keine Aktivität ausgeführt, daher sollte keine offene Sitzung außer der in der Speichermethode geöffneten Sitzung vorhanden sein
Laden vorhandener Daten mithilfe der Methode getInvoice und übergeben dieselben Daten nach dem Entfernen des Schlüsselwerts. Auch dies sollte meiner Meinung nach die Sitzung vor dem Speichern schließen, da die Transaktion in der getInvoice-Methode festgeschrieben wird.
In beiden Fällen wird dieselbe Fehlermeldung angezeigt, die mich zu der Annahme zwingt, dass entweder mit der Konfigurationsdatei im Ruhezustand oder mit Entitätsklassen oder der Speichermethode etwas nicht stimmt.
Bitte lassen Sie mich wissen, ob ich weitere Details angeben soll
Invoice
zuerst, damit die ID angezeigt wird, und speichern Sie sie dannInvoiceItem
. Sie können auch mit Kaskadierung spielen.Hier haben Sie den nativen Primärschlüssel verwendet und dem Primärschlüssel einen Wert zugewiesen. Der native Primärschlüssel wird automatisch generiert.
Daher kommt das Problem.
quelle
Dies ist in der Beziehung @ManyToOne vorhanden. Ich habe dieses Problem gelöst, indem ich nur CascadeType.MERGE anstelle von CascadeType.PERSIST oder CascadeType.ALL verwendet habe. Hoffe es hilft dir.
Lösung:
quelle
Höchstwahrscheinlich liegt das Problem außerhalb des Codes, den Sie uns hier zeigen. Sie versuchen, ein Objekt zu aktualisieren, das nicht der aktuellen Sitzung zugeordnet ist. Wenn es sich nicht um die Rechnung handelt, handelt es sich möglicherweise um ein InvoiceItem, das bereits beibehalten wurde, von der Datenbank abgerufen wurde, in einer Sitzung am Leben gehalten wurde, und dann versuchen Sie, es in einer neuen Sitzung beizubehalten. Das ist nicht möglich. Halten Sie Ihre persistierten Objekte in der Regel niemals über Sitzungen hinweg am Leben.
Die Lösung besteht darin, das gesamte Objektdiagramm aus derselben Sitzung zu erhalten, in der Sie versuchen, es beizubehalten. In einer Webumgebung würde dies bedeuten:
Wenn Sie weiterhin Probleme haben, veröffentlichen Sie einen Teil des Codes, der Ihren Dienst aufruft.
quelle
Zwei Lösungen: 1. Verwenden Sie Merge, wenn Sie das Objekt aktualisieren möchten. 2. Verwenden Sie save, wenn Sie nur ein neues Objekt speichern möchten (stellen Sie sicher, dass die Identität null ist, damit der Ruhezustand oder die Datenbank es generieren können.) 3. Wenn Sie eine Zuordnung wie
@OneToOne verwenden. fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn (name = "stock_id")
Verwenden Sie dann CascadeType.ALL für CascadeType.MERGE
danke Shahid Abbasi
quelle
Für JPA, das mit EntityManager behoben wurde, wird merge () anstelle von persist () verwendet.
quelle
Ich hatte das "gleiche" Problem, weil ich schrieb
Ich habe diese Zeile gelöscht, weil ich sie im Moment nicht brauche. Ich habe mit Objekten getestet und so. Ich denke es ist
<generator class="native" />
in deinem FallIch habe keinen Controller und auf meine API wird nicht zugegriffen, sondern nur zum Testen (im Moment).
quelle