Hibernate ленивый помощь при инициализации - PullRequest
1 голос
/ 21 сентября 2009

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

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);
} 

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

1 Ответ

3 голосов
/ 21 сентября 2009

Если вы просто хотите удалить родителя вместе с детьми, вам НЕ нужно загружать коллекцию детей. Вам даже не нужно 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. Напишите модульный тест, чтобы создать родительский / дочерний элемент в одной транзакции, зафиксировать его, удалить их во второй транзакции, зафиксировать его.
  3. Если (2) не работает, у вас проблема с отображением и / или схемой. Отправьте и здесь, и я посмотрю.
  4. Если (2) работает и ваш метод delete () выше не работает, у вас есть проблема где-то в вашем коде, где вызывается delete (). Возможно, вы загружаете тот же самый экземпляр Communication и перезаписываете его коллекцию communicationCountries.
...