2009-09-21 2 views
1

У меня проблема с удалением спящего режима. Когда я пытаюсь удалить, я получаю исключение, говорящее, что существуют дети, и есть нарушение FK. Я хочу также удалить детей, но удаление не похоже на каскадирование. Примерно через неделю, пытаясь исправить эту проблему, я прочитал, что должен использовать HibernateInterceptor, чтобы открыть сеанс, чтобы дети могли быть загружены. Когда я пытаюсь сделать это сейчас, я получаю следующее сообщение об ошибке:Hibernate lazy initialization help

Failed to load portlet com.blah.blah.CommunicationsPortlet: java.lang.ClassCastException: $Proxy27 incompatible with com.blah.blah.HibernateCommunicationsDAOImpl 

Вот выписка из моего файла отображения:

<set name="communicationCountries" inverse="true" cascade="all,delete-orphan"> 
<key column="COM_ID" not-null="true" on-delete="cascade" /> 
<one-to-many class="com.blah.blah.CommunicationCountry"/> 
</set> 

Вот выдержка из контекста приложения:

<bean id="hibernateCommunicationsDAOImplTarget" 
class="com.blah.blah.dao.impl.HibernateCommunicationsDAOImpl"> 
<property name="sessionFactory"> 
<ref bean="sessionFactory"/> 
</property> 
</bean> 

<bean id="hibernateCommunicationsDAOImpl" class="org.springframework.aop.framework.ProxyFactoryBean"> 
<property name="target"><ref bean="hibernateCommunicationsDAOImplTarget"/></property> 
<property name="proxyInterfaces"> 
<value>com.blah.blah.dao.CommunicationsDAO</value> 
</property> 
<property name="interceptorNames"> 
<list> 
<value>hibernateInterceptor</value> 
</list> 
</property> 
</bean> 

Вот мой метод в DAO:

public void deleteCommunication(Integer id) throws DataAccessException 
{ 
HibernateTemplate hibernate = getHibernateTemplate(); 
Communication existing = (Communication)hibernate.get(Communication.class, id); 
hibernate.initialize(existing.getCommunicationCountries()); 
hibernate.delete(existing); 
} 

Я действительно не знаю, что я делаю неправильно. У меня нет очень сложной схемы, только одна таблица, которая приводит к детям (странам). Любые идеи, что я мог бы сделать, чтобы исправить это?

+0

Вы загружаете сущность из dao, прежде чем пытаться ее удалить? то есть MyForm form = formdao.getForm(); Затем вы делаете свой form.delete(). – amischiefr

+0

Извините, я просмотрел hibernate.get в вашем коде. – amischiefr

ответ

3

Если вы просто хотите удалить родителя вместе с детьми, вам не нужно загружать коллекцию детей. Вам даже не нужно get() родителей, используя load() достаточно:

public void deleteCommunication(Integer id) throws DataAccessException { 
    HibernateTemplate hibernate = getHibernateTemplate(); 
    Communication existing = (Communication) hibernate.load(Communication.class, id); 
    hibernate.delete(existing); 
} 

Это, конечно, предполагает соответствующее отображение/каскад на месте. Выбранная выдержка отображения отображает ОК, за исключением <key ... on-delete="cascade"/>. Это довольно сложно по нескольким причинам:

  1. Ваша база данных должна поддерживать его, и ваша схема должна определить его. Вы получите сообщение об ошибке, если это не так.
  2. Вы не получите каких-либо улучшений производительности с этой настройкой, если для каскада установлено значение «ВСЕ», потому что Hibernate будет еще загрузить каждый дочерний объект, чтобы проверить дальнейшие ассоциации. Вам нужно установить каскад в «save-update», чтобы это работало, что затем имеет побочные эффекты для отношений между родителями и дочерними элементами с управляемым жизненным циклом.

Поэтому я предлагаю удалить on-delete="cascade" и не использовать его вообще, пока вы не поймете все последствия.

HibernateInterceptor, о котором вы упомянули, не имеет ничего общего со всем этим (скорее всего, не с методом delete(), как вы его кодировали); это часть подхода open-session-in-view к общению с уровнем пользовательского интерфейса.

Вот как устранить все выше:

  1. Избавьтесь от HibernateInterceptor сейчас.
  2. Напишите единичный тест для создания родительского/дочернего объекта в одной транзакции, зафиксируйте его, удалите в 2-й транзакции и зафиксируйте.
  3. Если (2) не работает, у вас возникли проблемы с отображением и/или схемой. Отправьте оба здесь, и я посмотрю.
  4. Если (2) работает и ваш метод delete() выше не работает, у вас есть проблема где-то в вашем коде, где вызывается delete(). Возможно, вы загрузили тот же экземпляр Communication и перезаписали его коллекцию communicationCountries.
+0

Я не уверен, почему, но это сработало для меня. очень странно, это то, что у меня было раньше, за исключением того, что я использовал .get() вместо .load(). Большое спасибо за помощь, я могу наконец расслабиться после недели, задаваясь вопросом, почему это не работает. – Caroline

+0

get() vs load() не должен иметь значения с ошибкой. Удаление 'on-delete = cascade' будет :-) – ChssPly76