Вопрос:

org.hibernate.PersistentObjectException: отдельная сущность передана, чтобы сохранить

hibernate

145684 просмотра

4 ответа

2307 Репутация автора

Я успешно написал свой первый пример главного ребенка с помощью 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>

РЕДАКТИРОВАТЬ: 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;
    }
}

РЕДАКТИРОВАТЬ: 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}]}

РЕДАКТИРОВАТЬ: Некоторые детали:
я попытался сохранить счет, используя два способа:

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

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

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

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

Автор: WSK Источник Размещён: 16.06.2011 08:59

Ответы (4)


3 плюса

3578 Репутация автора

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

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

  • Получить сессию
  • Получите объекты, которые нужно обновить или добавить ассоциации. Предпочтительнее по первичному ключу
  • Перешить что нужно
  • Сохранить / обновить / удалить / удалить то, что вы хотите
  • Закрыть / зафиксировать ваш сеанс / транзакцию

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

Автор: joostschouten Размещён: 16.06.2011 09:16

99 плюса

21963 Репутация автора

Решение

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

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

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

Автор: Alex Gitelman Размещён: 17.06.2011 05:42

10 плюса

118 Репутация автора

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

Отсюда и проблема.

Автор: Bibhav Размещён: 26.02.2014 05:23

1 плюс

37 Репутация автора

Это существует в отношении @ManyToOne. Я решил эту проблему, просто используя CascadeType.MERGE вместо CascadeType.PERSIST или CascadeType.ALL. Надеюсь, это поможет вам.

@ManyToOne(cascade = CascadeType.ALL)
@JoinColumn(name="updated_by", referencedColumnName = "id")
private Admin admin;

Решение:

@ManyToOne(cascade = CascadeType.MERGE)
@JoinColumn(name="updated_by", referencedColumnName = "id")
private Admin admin;
Автор: Kavitha yadav Размещён: 09.05.2019 09:50
Вопросы из категории :
32x32