JPA/Hibernate удалить сущность иногда не работает

У меня есть следующий код, который обычно работает хорошо:

public void delete(T object)
{
  EntityManager em = getPersistence().createEntityManager();
  EntityTransaction et = em.getTransaction();
  try
  {
    et.begin();
    object = em.find(object.getClass(), object.getId());
    em.remove(object);
    em.flush();
    et.commit();
  }
  catch(Exception e)
  {
    error("Unable to delete " + object.toString() + ": there are references to it.");
  }
  finally
  {
    if (et.isActive()) et.rollback();
    em.close();
  }
}

Для многих моих классов сущностей это просто работает. Однако для двух из них он ничего не делает, он не выдает никаких исключений и не удаляет объект. Журнал из hibernate показывает, что hibernate выполняет несколько запросов на выборку, но даже не пытается выполнить удаление.

Я уже попробовал предложения, найденные в других подобных вопросах здесь и здесь, но безрезультатно (ну, последний предлагает @Transactional который я не могу использовать, но я просто заключил заявления между begin() а также commit() вместо).

Я не могу найти то, что эти два класса имеют больше (или меньше), чем другие. Они используют @PrimaryKeyJoinColumn так же, как и почти все другие объекты, которые у меня есть, они имеют @OneToMany а также @ManyToOne так же, как охтер. Если честно, у них есть @OneToOne(optional = false) поле, которое ссылается на другой класс и которого другие объекты не имеют, но я бы не стал испытывать трудности с его изменением (и, следовательно, изменением схемы базы данных), если вы не скажете, что для этого может быть причина.

Является @OneToOne ответственность? Или мой код удаления прослушивается?

6 ответов

Решение

Есть ли у вас ассоциации на этом графике, которые каскадно сохраняют обратную связь с удаляемой вещью? Если это так, в спецификации JPA четко указано, что поставщик должен отменить удаление в таком случае. Если это так, Hibernate записывает запись в журнале, говоря "не планируя удаление объекта [...]". Это можно увидеть, включив запись трассировки на org.hibernate.event.internal.DefaultPersistEventListener регистратор.

Если это так, вам нужно очистить эти ассоциации в соответствии со спецификацией JPA.

Замена cascade = CascadeType.ALL от orphanRemoval = true в @OneToMany ассоциация дает ожидаемый результат: дочерние записи корректно удаляются без необходимости удаления родительской записи.

Жаль, что ошибка не записывается более четко.

Я получил ту же проблему, когда следующие вещи собрались вместе.

  1. Hibernate 3.6.10.Final
  2. Родительский объект без ссылки на Child.
  3. Некоторая дочерняя сущность со ссылкой на Родителя. Это устаревший код.

    class ChildEntity {
      @ManyToOne(cascade = CascadeType.ALL)
      private ParentEntity parent;
    }
    
  4. Дочерняя сущность загружается в контекст сеанса, а затем удаляется из таблицы без уведомления JPA внутри транзакции (хранимая процедура, собственный sql)

  5. Тогда родитель не может быть удален. Без удаления, без исключения, просто сообщение "не запланировать удаление" в журнале TRACE.

Решение: я удалил каскадный атрибут. Мне было немного трудно найти, какая дочерняя сущность блокирует удаление Родителя. Кроме того, я не понимаю, почему дочерний каскад влияет на удаление родительского объекта.

У меня была такая же проблема с сущностью, которая имеет много отношений. Что я сделал, так это установил обнуление родительских сущностей, произвел слияние, затем сделал сброс и очистку и, наконец, получил сущность снова, используя find и remove. Например:

objAgreement.setParent(null);
em.merge(objAgreement);
em.flush();
em.clear();

objAgreement= em.find(Agreement.class, objAgreement.getId())
em.remove(objAgreement);

Помимо всего этого, если у вас уже есть правильные значения каскадных и сиротских значений, в моем случае я обнаружил еще одну причину, по которой УДАЛЕНИЕ не может быть выполнено, даже если все выглядит нормально и даже когда УДАЛЕНО находятся в журнале, но база данных не показывает никаких изменений.,

Это также может быть транзакционной проблемой, но в моем случае это было то, что ключ (в Oracle Database) в запросе на удаление имел тип данных CHAR(8) в базе данных, в этом случае, как вы можете найти в документации Oracle CHAR по сравнению с VARCHAR2, если ваши данные не имеют длины 8, остальные покрыты пробелом, а в JPA DELETE делается различие между "0001" и "0001 ".

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

Приветствия.

Это не ответ на вопрос, но, возможно, это то, что вы ищете:

      @OneToMany(orphanRemoval = true,...)
Другие вопросы по тегам