У меня проблемы с однонаправленными двусторонними отношениями, которые я пытаюсь создать в Hibernate. При создании и сохранении нового потомка и родителя он пытается сохранить потомок с нулевой ссылкой на родителя. Просматривая журналы гибернации, он генерирует идентификаторы для обеих таблиц, затем устанавливает нулевую ссылку на родительский объект и выполняет запрос. Я совершенно сбит с толку.
В аннотированном классе родителя у меня есть:
@OneToOne
@JoinColumn(name = "CHILD_ID")
@Cascade(CascadeType.ALL)
private Child child;
В аннотированном классе ребенка у меня есть:
@OneToOne
@JoinColumn(name = "PARENT_ID")
private Parent parent;
Для создания / сохранения у меня есть:
Parent p = new Parent();
Child c = new Child();
p.setChild(c);
c.setParent(p);
getHibernateTemplate().save(p);
Журналы Hibernate, с интересными линиями, выделенными жирным шрифтом:
[org.springframework.orm.hibernate3.SessionFactoryUtils] [Opening Hibernate Session]
[org.hibernate.impl.SessionImpl] [opened session at timestamp: 13313040615]
[org.hibernate.event.def.DefaultSaveOrUpdateEventListener] [saving transient instance]
[org.hibernate.jdbc.AbstractBatcher] [opening JDBC connection]
[org.hibernate.SQL] [select UNQE_KEY_VALU from where UNQE_KEY_NAME = '' for update]
[org.hibernate.jdbc.AbstractBatcher] [closing JDBC connection (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
[org.hibernate.id.MultipleHiLoPerTableGenerator] [new hi value: 1413946]
[org.hibernate.event.def.AbstractSaveEventListener] [generated identifier: 14139460, using strategy: org.hibernate.id.MultipleHiLoPerTableGenerator]
[org.hibernate.event.def.AbstractSaveEventListener] [saving [Parent#14139460]]
[org.hibernate.engine.Cascade] [processing cascade ACTION_SAVE_UPDATE for: Parent]
[org.hibernate.engine.CascadingAction] [cascading to saveOrUpdate: Child]
[org.hibernate.engine.IdentifierValue] [id unsaved-value: 0]
[org.hibernate.event.def.AbstractSaveEventListener] [transient instance of: Child]
[org.hibernate.event.def.DefaultSaveOrUpdateEventListener] [saving transient instance]
[org.hibernate.jdbc.AbstractBatcher] [opening JDBC connection]
[org.hibernate.SQL] [select UNQE_KEY_VALU from where UNQE_KEY_NAME = '' for update]
[org.hibernate.jdbc.AbstractBatcher] [closing JDBC connection (open PreparedStatements: 0, globally: 0) (open ResultSets: 0, globally: 0)]
[org.hibernate.id.MultipleHiLoPerTableGenerator] [new hi value: 1413947]
[org.hibernate.event.def.AbstractSaveEventListener] [generated identifier: 14139470, using strategy: org.hibernate.id.MultipleHiLoPerTableGenerator]
[org.hibernate.event.def.AbstractSaveEventListener] [saving [Child#14139470]]
[org.hibernate.engine.Cascade] [done processing cascade ACTION_SAVE_UPDATE for: Child]
[org.hibernate.engine.Cascade] [processing cascade ACTION_SAVE_UPDATE for: Parent]
[org.hibernate.engine.Cascade] [done processing cascade ACTION_SAVE_UPDATE for: Parent]
[org.springframework.orm.hibernate3.HibernateTemplate] [Eagerly flushing Hibernate session]
[org.hibernate.event.def.AbstractFlushingEventListener] [flushing session]
[org.hibernate.event.def.AbstractFlushingEventListener] [processing flush-time cascades]
[org.hibernate.engine.Cascade] [processing cascade ACTION_SAVE_UPDATE for: Parent]
[org.hibernate.engine.CascadingAction] [cascading to saveOrUpdate: Child]
[org.hibernate.event.def.AbstractSaveEventListener] [persistent instance of: Child]
[org.hibernate.event.def.DefaultSaveOrUpdateEventListener] [ignoring persistent instance]
[org.hibernate.event.def.DefaultSaveOrUpdateEventListener] [object already associated with session: [Child#14139470]]
[org.hibernate.engine.Cascade] [done processing cascade ACTION_SAVE_UPDATE for: Parent]
[org.hibernate.event.def.AbstractFlushingEventListener] [dirty checking collections]
[org.hibernate.event.def.AbstractFlushingEventListener] [Flushing entities and processing referenced collections]
[org.hibernate.persister.entity.AbstractEntityPersister] [Child.parent is dirty]
[org.hibernate.event.def.DefaultFlushEntityEventListener] [Updating entity: [Child#14139470]]
[org.hibernate.event.def.AbstractFlushingEventListener] [Processing unreferenced collections]
[org.hibernate.event.def.AbstractFlushingEventListener] [Scheduling collection removes/(re)creates/updates]
[org.hibernate.event.def.AbstractFlushingEventListener] [Flushed: 2 insertions, 1 updates, 0 deletions to 2 objects]
[org.hibernate.event.def.AbstractFlushingEventListener] [Flushed: 0 (re)creations, 0 updates, 0 removals to 0 collections]
<b>[org.hibernate.pretty.Printer] [listing entities:]
[org.hibernate.pretty.Printer] [Parent{child=Child#14139470, parentId=14139460}]
[org.hibernate.pretty.Printer] [Child{parent=Parent#14139460, childId=14139470}]
</b>[org.hibernate.event.def.AbstractFlushingEventListener] [executing flush]
[org.hibernate.jdbc.ConnectionManager] [registering flush begin]
[org.hibernate.persister.entity.AbstractEntityPersister] [Inserting entity: [Child#14139470]]
[org.hibernate.jdbc.AbstractBatcher] [about to open PreparedStatement (open PreparedStatements: 0, globally: 0)]
[org.hibernate.jdbc.ConnectionManager] [opening JDBC connection]
<b>[org.hibernate.SQL] [insert into CHILD_TABLE (PARENT_ID, CHILD_ID) values (?, ?)]</b>
[org.hibernate.jdbc.AbstractBatcher] [preparing statement]
[org.hibernate.persister.entity.AbstractEntityPersister] [Dehydrating entity: [Child#14139470]]
<b>[org.hibernate.type.LongType] [binding null to parameter: 1]
[org.hibernate.type.LongType] [binding '14139470' to parameter: 2]</b>
[org.hibernate.persister.entity.AbstractEntityPersister] [Inserting entity: [Parent#14139460]]
[org.hibernate.jdbc.AbstractBatcher] [Executing batch size: 1]
[org.hibernate.jdbc.AbstractBatcher] [about to close PreparedStatement (open PreparedStatements: 1, globally: 1)]
[org.hibernate.jdbc.AbstractBatcher] [closing statement]
[DEBUG] [org.hibernate.util.JDBCExceptionReporter] [Could not execute JDBC batch update [insert into CHILD_TABLE (PARENT_ID, CHILD_ID) values (?, ?)]]
java.sql.BatchUpdateException: ORA-01400: cannot insert NULL into ("CHILD_TABLE"."PARENT_ID")
В первых двух жирных строках родитель знает идентификатор ребенка и наоборот. Однако при создании дочернего sql он устанавливает идентификатор родителя как ноль. Что происходит?
Edit:
В качестве ссылки я использую следующие спящие банки:
org.hibernate: спящая-аннотации: баночка: 3.3.1.GA
org.hibernate: спящий режим: баночка: 3.2.6.ga