org.hibernate.TransientObjectException в течение Criteria.list () - PullRequest
4 голосов
/ 09 апреля 2010

Я видел сообщения по всему Интернету, в которых говорится о том, как исправить TransientObjectExceptions во время сохранения / обновления / удаления, но у меня возникает эта проблема при вызове списка в моих критериях.

У меня есть два объекта A иB. A имеет поле с именем b, которое имеет тип B. В моем отображении b отображается как многие-к-одному.Все это работает в более крупном постоянном фреймворке (фреймворк похож на Core Data), и поэтому я не использую никаких каскадов в моих отображениях гибернации, поскольку каскады обрабатываются на более высоком уровне.

Это интереснокод, соответствующий моим критериям:

A a = new A();
B b = new B();
a.setB(b);

session.save("B", b); // Actually handled by the higher level
session.save("A", a); // framework, this is just for clarity

// transaction committed and session closed
...
// new session opened

Criteria criteria = session.createCriteria(A.class);
criteria.add(Restrictions.eq("b", b));
List<?> objects = criteria.list();

В основном я ищу все объекты типа A, так что Ab равен конкретному экземпляру b (я фактически пытался реструктурировать запрос так, чтобы я передавал идентификатор bпросто чтобы убедиться, что b не вызывает у меня проблем).

Вот трассировка стека, которая происходит, когда я вызываю attribute.list ():

org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: B
at org.hibernate.engine.ForeignKeys.getEntityIdentifierIfNotUnsaved(ForeignKeys.java:244)
at org.hibernate.type.EntityType.getIdentifier(EntityType.java:449)
at org.hibernate.type.ManyToOneType.nullSafeSet(ManyToOneType.java:141)
at org.hibernate.loader.Loader.bindPositionalParameters(Loader.java:1769)
at org.hibernate.loader.Loader.bindParameterValues(Loader.java:1740)
at org.hibernate.loader.Loader.prepareQueryStatement(Loader.java:1612)
at org.hibernate.loader.Loader.doQuery(Loader.java:717)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:270)
at org.hibernate.loader.Loader.doList(Loader.java:2294)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2172)
at org.hibernate.loader.Loader.list(Loader.java:2167)
at org.hibernate.loader.criteria.CriteriaLoader.list(CriteriaLoader.java:119)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1706)
at org.hibernate.impl.CriteriaImpl.list(CriteriaImpl.java:347)

Вот мое отображение:

<class entity-name="A" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
<many-to-one name="b" entity-name="B" column="b_id" lazy="false" />
</class>

<class entity-name="B" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
</class>

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

Ответы [ 3 ]

1 голос
/ 09 апреля 2010

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

session.update(b);

Цитата из книги Hibernate:

Операция update() на сеансе присоединяет отсоединенный объект к контексту постоянства и планирует SQL UDPATE. Hibernate должен предполагать, что клиент изменил объект пока он был оторван. (В противном случае, если вы уверены, что он не был изменен, lock() будет достаточно.) Постоянный контекст сбрасывается автоматически когда вторая транзакция в разговоре фиксируется, и любой изменения в когда-то отделенном и теперь постоянном объекте синхронизируются с базой данных.

Метод saveOrUpdate() на практике более полезен, чем update(), save() или lock(): в сложных разговорах вы не знаете, находится ли предмет в отключенное состояние или если оно новое и временное и должно быть сохранено. Автоматический обнаружение состояний, предоставляемое saveOrUpdate(), становится еще более полезным, когда вы не только работать с единичными экземплярами, но также хочет заново подключить или сохранить сеть подключенных объектов и применять каскадные параметры.

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

0 голосов
/ 20 декабря 2012

Поскольку у вас есть данные вставки, такие как в persist (), save () в hibernate .. Но вышеприведенная ошибка заключается в том, что вы просто используете метод merge () и другие, которые могут выполнять обновление информации.

0 голосов
/ 12 мая 2010

Другой простой способ сделать то же самое - использовать атрибут cascade = all в отображении коллекции дочернего класса из отображения родительского класса. Вот как выглядит отображение

<class entity-name="A" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
<many-to-one name="b" entity-name="B" column="b_id" lazy="false" cascade="all" />
</class>

<class entity-name="B" lazy="false">
<tuplizer entity-mode="dynamic-map" class="MyTuplizer" />
<id type="long" column="id">
<generator class="native" />
</id>
</class>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...