Z powodzeniem napisałem mój pierwszy przykład dziecka-mistrza z hibernacją. Po kilku dniach wziąłem go ponownie i zaktualizowałem niektóre biblioteki. Nie jestem pewien, co zrobiłem, ale nigdy nie mogłem sprawić, by znowu działał. Czy ktoś pomoże mi dowiedzieć się, co jest nie tak w kodzie, który zwraca następujący komunikat o błędzie:
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)
mapowanie hibernacji:
<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>
EDYCJA: 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;
}
}
EDYCJA: obiekt JSON wysłany z klienta:
{"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}]}
EDYCJA: Niektóre szczegóły:
Próbowałem zapisać fakturę na dwa sposoby:
Ręcznie sfabrykowany powyższy obiekt json i przekazany do nowej sesji serwera. W tym przypadku żadna czynność nie została wykonana przed wywołaniem metody save, więc nie powinno być żadnej otwartej sesji poza tą otwartą metodą save
Załadowano istniejące dane przy użyciu metody getInvoice i przekazały te same dane po usunięciu wartości klucza. Uważam, że to również powinno zamknąć sesję przed zapisaniem, ponieważ transakcja jest zatwierdzana w metodzie getInvoice.
W obu przypadkach pojawia się ten sam komunikat o błędzie, który zmusza mnie do przekonania, że coś jest nie tak z plikiem konfiguracyjnym hibernacji lub klasami jednostek lub metodą zapisywania.
Daj mi znać, jeśli mam podać więcej szczegółów
Invoice
najpierw, aby uzyskać id, a następnie zapiszInvoiceItem
. Możesz także grać kaskadowo.Tutaj użyłeś natywnego i przypisanie wartości do klucza podstawowego, w natywnym kluczu podstawowym jest generowany automatycznie.
Stąd problem nadchodzi.
źródło
To istnieje w relacji @ManyToOne. Rozwiązałem ten problem, używając po prostu CascadeType.MERGE zamiast CascadeType.PERSIST lub CascadeType.ALL. Mam nadzieję, że ci to pomoże.
@ManyToOne(cascade = CascadeType.ALL) @JoinColumn(name="updated_by", referencedColumnName = "id") private Admin admin;
Rozwiązanie:
@ManyToOne(cascade = CascadeType.MERGE) @JoinColumn(name="updated_by", referencedColumnName = "id") private Admin admin;
źródło
Najprawdopodobniej problem leży poza kodem, który nam pokazujesz. Próbujesz zaktualizować obiekt, który nie jest powiązany z bieżącą sesją. Jeśli nie jest to faktura, to może jest to element InvoiceItem, który został już utrwalony, uzyskany z bazy danych, utrzymany przy życiu w jakiejś sesji, a następnie próbujesz utrwalić go w nowej sesji. To jest niemożliwe. Zasadniczo nigdy nie utrzymuj trwałych obiektów przy życiu podczas sesji.
Rozwiązaniem będzie np. Uzyskanie całego grafu obiektu z tej samej sesji, z którą próbujesz go utrwalić. W środowisku internetowym oznaczałoby to:
Jeśli nadal masz problemy, opublikuj kod wywołujący usługę.
źródło
Dwa rozwiązania 1. użyj scalania, jeśli chcesz zaktualizować obiekt 2. użyj zapisz, jeśli chcesz po prostu zapisać nowy obiekt (upewnij się, że tożsamość jest zerowa, aby umożliwić hibernację lub wygenerowanie przez bazę danych) 3. jeśli używasz mapowania, takiego jak
@OneToOne ( fetch = FetchType.EAGER, cascade = CascadeType.ALL) @JoinColumn (name = "stock_id")
Następnie użyj CascadeType.ALL do CascadeType.MERGE
dzięki Shahid Abbasi
źródło
W przypadku JPA naprawiono za pomocą EntityManager merge () zamiast persist ()
EntityManager em = getEntityManager(); try { em.getTransaction().begin(); em.merge(fieldValue); em.getTransaction().commit(); } catch (Exception e) { //do smthng } finally { em.close(); }
źródło
Miałem „ten sam” problem, ponieważ pisałem
@GeneratedValue(strategy = GenerationType.IDENTITY)
Usunąłem tę linię, ponieważ w tej chwili jej nie potrzebuję, testowałem z obiektami i tak dalej. Myślę, że tak jest
<generator class="native" />
w twoim przypadkuNie mam żadnego kontrolera, a moje API nie jest dostępne, służy tylko do testowania (w tej chwili).
źródło