орг.зимовать.PersistentObjectException: отсоединенный объект передается для сохранения


я успешно написал свой первый пример master child с hibernate. Через несколько дней я снова взял его и обновил некоторые библиотеки. Не знаю, что я сделал, но я никогда не мог заставить его работать снова. Кто-нибудь поможет мне выяснить, что не так в коде, который возвращает следующее сообщение об ошибке:

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

счет-фактура.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, отправленный от клиента:

{"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: некоторые детали:
Я попытался сохранить счет, выполнив следующие два способа:

  1. вручную изготовлено выше упомянуто JSON-объект и передал его на свежий сессия сервера. В данном случае абсолютно никакая деятельность не была сделана до зовущий сохранить метод, так что не должно быть никакого открытого сеанса кроме того, который открыт в методе сохранения

  2. загружены существующие данные с помощью getInvoice метод и их передали же данные после удаления значения ключа. Это тоже я считаю необходимо закрыть сеанс перед сохранением транзакция фиксируется в методе getInvoice.

в обоих случаях я получаю то же сообщение об ошибке, что заставляет меня верить, что что-то не так либо с hibernate конфигурационный файл или классы сущностей или метод сохранения.

пожалуйста, дайте мне знать, если я должен предоставить больше деталей

3 67

3 ответа:

вы не предоставили много соответствующих деталей, поэтому я догадаюсь, что вы позвонили getInvoice и затем вы использовали объект результата, чтобы установить некоторые значения и вызвать save с предположением, что изменения объекта будут сохранены.

однако, persist операция предназначена для совершенно новых переходных объектов и завершается неудачей, если id уже назначен. В вашем случае вы, вероятно, хотите позвонить saveOrUpdate вместо persist.

вы можете найти некоторые обсуждения и ссылки здесь "отсоединенный объект передан для сохранения ошибки" с кодом JPA/EJB

здесь вы использовали native и присвоение значения первичному ключу, в native первичный ключ генерируется автоматически.

следовательно, вопрос идет.

скорее всего проблема лежит за пределами кода, который вы показываете нам здесь. Вы пытаетесь обновить объект, который не связан с текущим сеансом. Если это не Счет-фактура, то, возможно, это InvoiceItem, который уже был сохранен, получен из БД, сохранен в каком-то сеансе, а затем вы пытаетесь сохранить его в новом сеансе. Это невозможно. Как правило, никогда не сохраняйте сохраненные объекты живыми во время сеансов.

решение будет ie при получении всего графа объекта из того же сеанса вы пытаетесь сохранить его. В веб-среде, это будет означать:

  • получить сеанс!--6-->
  • выберите объекты, которые необходимо обновить или добавить ассоциации. Preferabley по их первичному ключу
  • изменить то, что нужно
  • сохранить / обновить / выселить / удалить то, что вы хотите
  • закрыть / зафиксировать сеанс / транзакцию

Если вы продолжаете иметь проблемы разместить некоторые из код, который вызывает вашу службу.