删除EventListener中的实体

时间:2012-04-03 14:17:00

标签: java hibernate entity relationship

我现在正在使用Hibernate 4.1.1很长一段时间。 下面:我创建了一个EventListener,它由Hibernate的Integrator接口集成。到目前为止,这有效!

我正在尝试删除实体,例如帐户。 帐户与播放列表具有一对多的关系。

我想要实现的目标: 删除帐户时删除播放列表。

我知道我可以通过向Hibernate Mappings添加级联行为来实现这一点。 到目前为止,这将工作,但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. 在onPreDelete中调用commit会导致StackOverflowError(它无休止地提交delete playlistEntry查询)
  3. 如果查询未在onPreDelete方法中提交,则将执行查询,但Swing应用程序开始永远冻结。
  4. 不删除播放列表会导致外键无操作异常
  5. 那我怎么解决呢?

1 个答案:

答案 0 :(得分:1)

提交事务上的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;
} 

当然,您可以通过复合键或实体锁定它(如果它具有哈希码+等于实现)。但这是如何解决它的一般原则。