Hibernate не правильно каскадные двунаправленные отношения - PullRequest
0 голосов
/ 09 марта 2012

У меня проблемы с однонаправленными двусторонними отношениями, которые я пытаюсь создать в 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

Ответы [ 2 ]

6 голосов
/ 09 марта 2012

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

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

Кстати, такой способ может привести к ситуации, когда у родителя A есть ребенок B, у которого есть родитель C.

Если вы действительно хотите двунаправленную связь «один к одному», вы должны удалить один из внешних ключей и использовать другой для сопоставления ассоциации. Предположим, что вы сохраняете столбец CHILD_ID в родительской таблице, тогда сопоставление будет:

@OneToOne
@JoinColumn(name = "CHILD_ID")
@Cascade(CascadeType.ALL)
private Child child;

и

@OneToOne(mappedBy = "child")
private Parent parent;
0 голосов
/ 12 марта 2012

Я исправил это, хотя я не уверен, почему это работает.Я переместил каскад с Родителя на Ребенка и сохранил Дочернего вместо Родителя.

В аннотированном классе родителя у меня есть:

@OneToOne
@JoinColumn(name = "CHILD_ID")
private Child child;

В аннотированном классе ребенка у меня есть:

@OneToOne
@JoinColumn(name = "PARENT_ID")
@Cascade(CascadeType.ALL)
private Parent parent;

Для создания / сохранения у меня есть:

Parent p = new Parent();
Child c = new Child();
p.setChild(c);
c.setParent(p);
getHibernateTemplate().save(c);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...