Hibernate каскадное удаление не работает - PullRequest
1 голос
/ 17 сентября 2009

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

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

Вот отображение для дочернего класса:

<many-to-one name="communication" column="COM_ID" not-null="true" class="com.fmr.fc.portlet.communications.vo.Communication" cascade="all"/>

РЕДАКТИРОВАТЬ - Когда я делаю вставку, данные вставляются в родительский и дочерний.

Когда я делаю обновление, используя новый объект с идентификатором объекта, который я хочу изменить, родительский объект обновляется, но все существующие дочерние элементы добавляются во второй раз. Я не могу удалить детей. Когда я получаю объект, используя идентификатор и изменяю его, я получаю сообщение об ошибке org.hibernate.LazyInitializationException: не удалось инициализировать прокси-сервер - сеанс-владелец был закрыт. Я подозреваю, что это потому, что в одном вызове getHibernateTemplate () я получаю объект и сохраняю его в другом, и это два разных сеанса?

Когда я делаю удаление, я получаю ошибку, потому что дети существуют. Я знаю, что просто делаю что-то глупое из-за отсутствия понятия о том, как все это работает.

Вот мои методы обновления и удаления, в этом случае обновление / сохранение извлекается и изменяется перед сохранением. Для удаления используется новый объект с тем же идентификатором, что и в БД, которую я хочу удалить:

public void deleteCommunication(Communication comm) throws DataAccessException 
{
    getHibernateTemplate().delete(comm);
}

public void saveCommunication(Communication comm) throws DataAccessException
{       
    Communication existing = (Communication)getHibernateTemplate().load(Communication.class, comm.getComId());
    existing.getCommunicationCountries().clear();

    getHibernateTemplate().saveOrUpdate(existing);      
}

UPDATE Итак, вот мои новые методы, но до сих пор нет радости. Я думаю, что моя проблема связана с тем, что потомки не загружаются / не инициализируются и т. Д. С удалением я не могу понять, почему не происходит каскадное удаление.

Большое спасибо за вашу помощь. У меня уже установлен срок выполнения этой работы, поэтому, если я не исправлю его в выходные, мне просто придется прибегнуть к выполнению HQL-запросов, поскольку я знаю, что это будет работать для меня: (

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

    public void updateCommunication(Communication comm) throws DataAccessException
    {       
        HibernateTemplate hibernate = getHibernateTemplate();
        Communication existing = (Communication)hibernate.get(Communication.class, comm.getComId());
        hibernate.initialize( existing.getCommunicationCountries());
        existing.getCommunicationCountries().clear();
        hibernate.saveOrUpdate(existing);       
    }

1 Ответ

2 голосов
/ 17 сентября 2009

В произвольном порядке:

A) Предполагая, что "myID" в вашем коде является идентификатором вашей сущности, вы должны использовать session.get () вместо критериев - это быстрее и определенно проще:

MyObject obj = (MyObject) session.get(MyObject.class, new Long(1));

B) Если вы используете Spring (судя по вызову getHibernateTemplate()), вы должны использовать его последовательно :-) и не прибегать к непосредственному вызову сеанса, если в этом нет крайней необходимости - и это почти никогда не требуется , Таким образом, приведенный выше метод get станет:

MyObject obj = (MyObject) getHibernateTemplate().get(MyObject.class, new Long(1));

Если вам нужно написать запрос на основе критериев, вы можете использовать DetachedCriteria и HibernateTemplate.getByCriteria() метод:

DetachedCriteria crit = DetachedCriteria.forClass(MyObject.class)
 .add(Property.forName("myId").eq( new Long(1) ) );
List results = getHibernateTemplate().findByCriteria(crit);

C) Обычно вы не должны evict() возражать из сеанса (делать это непосредственно перед закрытием в любом случае довольно бессмысленно). Как правило, вы не должны close() сеанс, который вы получили от HibernateTemplate.

D) Наконец, что касается автоматического сохранения дочерних элементов (элементов коллекции «один ко многим»), взгляните на этот пример , который дает хорошее объяснение различных каскадов настройки. Если у вас все еще есть проблемы, опубликуйте свои сопоставления / код.

Обновление (на основе уточнений вопроса):

1) Ваше отображение выглядит нормально, за исключением каскада родительского в дочернем классе (<many-to-one name="communication" cascade="all"/>). Вы, скорее всего, не хотите этого.

2) LazyInitializationException выбрасывается, поскольку Hibernate по умолчанию отображает коллекции как ленивые, что означает, что дочерние элементы (communicationCountries) не будут загружены до первого доступа. Если такой доступ происходит, когда сеанс уже закрыт, генерируется исключение. Вы можете убедиться, что коллекция заполнена, вызвав Hibernate.initialize() на коллекции.

3) Функция delete () должна работать как ДОЛГО, КАК вы вызываете ее для экземпляра сущности, возвращенного Hibernate, а не для того, который вы создали сами (скажем, unmarshalled из удаленного вызова), для которого коллекция "communicationCountries" не подходит населен. Чтобы Hibernate удалил детей, он должен знать, что они существуют.

4) С другой стороны, ваше обновление () неверно. Вы загружаете сущность, очищаете ее дочерние элементы и сохраняете ее снова - что само по себе хорошо - но это никак не связано с передаваемым параметром.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...