Удалить объекты в EventListener - PullRequest
0 голосов
/ 03 апреля 2012

Я работаю с Hibernate 4.1.1 довольно давно.Следующее: я создал EventListener, который интегрирован с интерфейсом интегратора Hibernate.Пока это работает!

Я пытаюсь удалить сущность, например, учетную запись.Учетная запись имеет отношение «один ко многим» к плейлистам.

Чего я хочу добиться: удалять плейлисты при удалении учетной записи.

Я знаю, что могу добиться этого, добавив каскадное поведение в мой HibernateОтображения.До сих пор это работало, но Hibernate не может предоставить функциональность для установки значения NULL на каскаде, поэтому я хотел сделать эти шаги вручную:

@Override public boolean onPreDelete(final PreDeleteEvent preDeleteEvent) throws HibernateException
{
    if (preDeleteEvent.getEntity() instanceof PresetEntry) {
    } else if (preDeleteEvent.getEntity() instanceof AccountEntry) {
        final Session session = this.sessionFactory.getCurrentSession();

        if (!session.getTransaction().isActive()) {
            session.getTransaction().begin();
        }
        final AccountEntry accountEntry = (AccountEntry) preDeleteEvent.getEntity();
        session.createQuery("DELETE FROM PlaylistEntry WHERE ACCOUNT_ID = " + accountEntry.getIdentity()).executeUpdate(); //NON-NLS
    } else if (preDeleteEvent.getEntity() instanceof PlaylistEntry) {

    } else if (preDeleteEvent.getEntity() instanceof QueueEntry) {

    }
    return false;
}

Я работаю в следующих вопросах:

  1. Транзакция уже открыта, поскольку учетная запись в настоящий момент удалена
  2. Вызов commit в onPreDelete приводит к StackOverflowError (он бесконечно фиксирует запрос на удаление playlistEntry)
  3. Еслизапрос не передается внутри метода onPreDelete, запросы будут выполняться, однако приложение Swing начинает зависать навсегда.
  4. Не удаление списков воспроизведения приводит к тому, что внешний ключ не вызывает исключений

Так как я могу решить это?

1 Ответ

1 голос
/ 04 апреля 2012

StackOverflow при совершении транзакции происходит, потому что он вызывает обработчик onPreDelete снова (и снова, и снова).Во избежание этого вам нужно обнаружить (внутри слушателя), что вы уже обработали удаление этого объекта.Это можно сделать следующим образом:

    private final Collection<Long> processingAccounts = 
       Collections.newSetFromMap(new ConcurrentHashMap<Long, Boolean>());
    ...
    @Override public boolean onPreDelete(final PreDeleteEvent preDeleteEvent) 
       throws HibernateException  {
         ....
    } else if (preDeleteEvent.getEntity() instanceof AccountEntry) {
           // check if it's already been processed
           if (processingAccounts.contains(preDeleteEvent.getEntity().getId()) 
              return false;
           // block it by ID
           processingAccounts.add(preDeleteEvent.getEntity().getId();
           try {

             ....
           } finally {
              // release
              processingAccounts.remove(preDeleteEvent.getEntity().getId()
           }
    }
    return false;
} 

Конечно, вы можете заблокировать его с помощью составного ключа или объекта (если в нем реализован хэш-код + равнозначный).Но это общий принцип, как это можно решить.

...