Вопрос по java – IllegalStateException с Hibernate 4 и ManyToOne каскадным

23

Я получил эти два класса

MyItem Object:

<code>@Entity
public class MyItem implements Serializable {

    @Id
    private Integer id;
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Component defaultComponent;
    @ManyToOne(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
    private Component masterComponent;

    //default constructor, getter, setter, equals and hashCode
}
</code>

Компонент Объект:

<code>@Entity
public class Component implements Serializable {

    @Id
    private String name;

    //again, default constructor, getter, setter, equals and hashCode
}
</code>

И я пытаюсь сохранить те, которые имеют следующий код:

<code>public class Test {

    public static void main(String[] args) {
        Component c1 = new Component();
        c1.setName("comp");
        Component c2 = new Component();
        c2.setName("comp");
        System.out.println(c1.equals(c2)); //TRUE

        MyItem item = new MyItem();
        item.setId(5);
        item.setDefaultComponent(c1);
        item.setMasterComponent(c2);

        ItemDAO itemDAO = new ItemDAO();
        itemDAO.merge(item);
    }
}
</code>

Хотя это нормально работает с Hibernate 3.6, Hibernate 4.1.3 выбрасывает

<code>Exception in thread "main" java.lang.IllegalStateException: An entity copy was already assigned to a different entity.
        at org.hibernate.event.internal.EventCache.put(EventCache.java:184)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:285)
        at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
        at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:914)
        at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:896)
        at org.hibernate.engine.spi.CascadingAction$6.cascade(CascadingAction.java:288)
        at org.hibernate.engine.internal.Cascade.cascadeToOne(Cascade.java:380)
        at org.hibernate.engine.internal.Cascade.cascadeAssociation(Cascade.java:323)
        at org.hibernate.engine.internal.Cascade.cascadeProperty(Cascade.java:208)
        at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:165)
        at org.hibernate.event.internal.AbstractSaveEventListener.cascadeBeforeSave(AbstractSaveEventListener.java:423)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:213)
        at org.hibernate.event.internal.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:282)
        at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:151)
        at org.hibernate.event.internal.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:76)
        at org.hibernate.internal.SessionImpl.fireMerge(SessionImpl.java:904)
        at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:888)
        at org.hibernate.internal.SessionImpl.merge(SessionImpl.java:892)
        at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:874)
        at sandbox.h4bug.Test$GenericDAO.merge(Test.java:79)
        at sandbox.h4bug.Test.main(Test.java:25)
</code>

Бэкэнд базы данных - h2 (но то же самое происходит с hsqldb или derby). Что я делаю неправильно?

Ваш Ответ

9   ответов
5

То же самое здесь, проверьте ваш метод equals (). Скорее всего плохо реализовано.

Редактировать: Я убедился, что операция слияния не будет работать, если вы не правильно реализуете методы Equity () и hashCode () вашего Entity.

Вы должны следовать этим рекомендациям для реализации equals () и hashCode ():

http://docs.jboss.org/hibernate/orm/4.1/manual/en-US/html/ch04.html#persistent-classes-equalshashcode

"It is recommended that you implement equals() and hashCode() using Business key equality. Business key equality means that the equals() method compares only the properties that form the business key. It is a key that would identify our instance in the real world (a natural candidate key)"

Это означает: вы НЕ должны использовать свой Id как часть вашей реализации equals ()!

Error: User Rate Limit Exceededblog.andrewbeacock.com/2008/08/…
0

У меня была такая же проблема, только что решил ее. Хотя приведенные выше ответы могут решить проблему, я не согласен с некоторыми из них, особенно с изменением реализованных методов equlas () и hashcode (). Однако я чувствую, что мой ответ усиливает @Tobb и @Supun s & apos; Ответ (ы).

На моей Многой стороне (детской стороне) я имел

 @OneToMany(mappedBy = "authorID", cascade =CascadeType.ALL, fetch=FetchType.EAGER)
 private Colllection books;

И с моей стороны (родительская сторона)

 @ManyToOne(cascade =CascadeType.ALL)
 private AuthorID authorID;

Прочитав превосходный топ-ответ, предоставленный @Tobb, и немного подумав, я понял, что аннотации не имеют смысла. В моем понимании (в моем случае) я слил () объект Author и слил () книгу Object. Но поскольку коллекция книг является компонентом объекта Author, она пыталась сохранить его дважды. Мое решение состояло в том, чтобы изменить типы каскада на:

  @OneToMany(mappedBy = "authorID", cascade =CascadeType.PERSIST, fetch=FetchType.EAGER)
  private Collection bookCollection;

а также

 @ManyToOne(cascade =CascadeType.MERGE)
 private AuthorID authorID;

Короче говоря, сохраните родительский объект и объедините дочерний объект.

Надеюсь, что это помогает / имеет смысл.

0

Попробуйте добавить@GeneratedValue аннотация под@Id в классе компонентов. в противном случае два разных экземпляра могут получить один и тот же идентификатор и col, lide.

Похоже, вы даете им тот же идентификатор.

    Component c1 = new Component();
    c1.setName("comp");
    Component c2 = new Component();
    c2.setName("comp");

Это может решить вашу проблему.

Error: User Rate Limit Exceeded Clayton Louden
Error: User Rate Limit Exceeded Clayton Louden
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
4

Ваши отношения между предметом и компонентомunidirectional или жеbidirectional? Если это двунаправленный, убедитесь, что у вас нетCascade.MERGE звонки возвращаются к пункту.

По сути, более новая версия Hibernate имеет карту сущностей, которая содержит список всех вещей, которые должны быть объединены на основе вызова merge (), он вызовет слияние, а затем перейдет к следующему, но сохранит вещи на карте, он выдаст ошибку, о которой вы заявили выше "Копия объекта уже была назначена другому объекту" когда он встречает предмет, с которым уже разобрались. Мы нашли в нашем приложении, когда нашли эти «вверх» сливается в графе объектов т.е. в двунаправленных ссылках исправлен вызов слияния.

0

Если имя является идентификатором, почему вы создаете два объекта с одинаковым идентификатором ?? Вы можете использовать объект c1 во всем коде.

Если это только пример и вы создаете объект c2 в другой части кода, то вам не нужно создавать новый объект, а загружать его из базы данных:

c2 = itemDao.find("comp", Component.class); //or something like this AFTER the c1 has been persisted
27

У меня была такая же проблема, и вот что я нашел:

Метод слияния просматривает график объекта, который вы хотите сохранить, и для каждого объекта в этом графике он загружает его из базы данных, поэтому у него есть пара (постоянная сущность, отдельная сущность) для каждого объекта в графе, где Отдельная сущность - это сущность, которая будет сохранена, а постоянная сущность получена из базы данных. (В способе, а также в сообщении об ошибке постоянный объект известен как «копия»). Затем эти пары помещаются в две карты, одна с постоянным объектом в качестве ключа и отсоединенным объектом в качестве значения, а другая с отсоединенным объектом в качестве ключа и постоянным объектом в качестве значения.

Для каждой такой пары объектов он проверяет эти карты, чтобы увидеть, отображается ли постоянный объект на тот же отдельный объект, что и раньше (если он уже был посещен), и наоборот. Эта проблема возникает, когда вы получаете пару сущностей, где выполнение get с персистентной сущностью возвращает значение, а get с другой карты с отсоединенной сущностью возвращает значение null, что означает, что вы уже связали персистентную сущность с отделенной сущностью. сущность с другим хеш-кодом (в основном это идентификатор объекта, если вы не переопределили метод хеш-кода).

TL; DR, у вас есть несколько объектов с разными идентификаторами объектов / хэш-кодами, но с одним и тем же идентификатором постоянства (таким образом, ссылаясь на один и тот же постоянный объект). Это, по-видимому, больше не разрешено в более новых версиях Hibernate4 (4.1.3. Наконец и выше, что я мог сказать).

Сообщение об ошибке не очень хорошее IMO, что он действительно должен сказать что-то вроде:

A persistent entity has already been assigned to a different detached entity

или же

Multiple detached objects corresponding to the same persistent entity

Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceeded
Error: User Rate Limit Exceededhibernate.atlassian.net/browse/HHH-7605
0

если вы используете jboss EAP 6 .. измените его на jboss 7.1.1. Это ошибка jboss EAP 6. https://access.redhat.com/documentation/en-US/JBoss_Enterprise_Application_Platform/6.3/html/6.3.0_Release_Notes/ar01s07s03.html

Error: User Rate Limit Exceeded
2

Было то же исключение (hibernate 4.3.0.CR2), утомляющее сохранение объекта, который имеет две копии дочернего объекта, был зафиксирован, в сущности от :

@OneToOne(cascade = CascadeType.MERGE)
private User reporter;
@OneToOne(cascade = CascadeType.MERGE)
private User assignedto;

чтобы просто,

@OneToOne
private User reporter;
@OneToOne
private User assignedto;

хотя я не знаю причину

0

Согласно логике в EventCache все сущности в графе объектов должны быть уникальными. Таким образом, лучшее решение (или это обходной путь?) Состоит в том, чтобы удалить каскад в MyItem для компонента. И объединять Компонент отдельно, если это действительно необходимо - я бы поспорил, что в 95% случаев Компонент не должен быть объединен в соответствии с бизнес-логикой.

С другой стороны - мне действительно интересно узнать реальные мысли, стоящие за этим ограничением.

Похожие вопросы