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 выполняет несколько запросов выбора, но даже не пытается выполнить удаление.
Я уже пробовал предложения, найденные в других подобных вопросах здесь и здесь, но безрезультатно (ну, последнее предлагает @Transactional
, который я не могу использовать, но я просто заключил в себе выражения между begin()
и commit()
).
Я не могу найти, что эти два класса имеют больше (или меньше), чем другие. Они используют @PrimaryKeyJoinColumn
так же, как и почти все другие объекты, которые у меня есть, они имеют @OneToMany
и @ManyToOne
точно так же, как ohters. Честно говоря, у них есть поле @OneToOne(optional = false)
, которое ссылается на другой класс, а другие объекты не имеют, но я бы не стал обсуждать проблему изменения этого (и, следовательно, изменения схемы базы данных), если вы не скажете мне, что можно быть причиной для этого.
Является ли @OneToOne
ответственным? Или мой код удаления прослушивается?
Ответы
Ответ 1
Есть ли у вас ассоциации на этом графике, которые каскадно сохраняют обратно к удаляемой вещи? Если это так, спецификация JPA четко указывает, что провайдер должен отменить удаление в таком случае. Если это так, Hibernate выписывает выражение журнала, в котором говорится: "Отмена удаления объекта [...]". Это можно увидеть, включив ведение журнала трассировки в журнале org.hibernate.event.internal.DefaultPersistEventListener
.
Если это так, вам нужно очистить эти ассоциации, как того требует спецификация JPA.
Ответ 2
Замена cascade = CascadeType.ALL
на orphanRemoval = true
в ассоциации @OneToMany
дает ожидаемый результат: дочерние записи удаляются без необходимости удаления родительской записи.
Жаль, что ошибка не регистрируется более четко.
Ответ 3
У меня возникла такая же проблема, когда мы собрали все вместе.
- Hibernate 3.6.10.Final
- Родительский объект с no ссылкой на Child.
-
Некоторые дочерние объекты со ссылкой на родителя. Это устаревший код.
class ChildEntity {
@ManyToOne(cascade = CascadeType.ALL)
private ParentEntity parent;
}
-
дочерний объект загружается в контекст сеанса, а затем удаляется из таблицы без уведомления JPA в транзакции (хранимая процедура, собственный sql)
-
Затем родительский элемент нельзя удалить. Отсутствие исключения, исключение, просто сообщение "расписание удаления" в журнале TRACE.
Решение: я удалил атрибут каскада. Мне было немного сложно найти, какой дочерний объект блокирует удаление родителя. Кроме того, я не понимаю, почему Child Cascade влияет на удаление родительского объекта.
Ответ 4
Помимо всего этого, если у вас уже есть правильные значения каскадных и сиротских значений, в моем случае я обнаружил еще одну причину, по которой УДАЛЕНИЕ не может быть выполнено, даже если все выглядит нормально и даже когда УДАЛЕНО находятся в журнале, но база данных не показывает никаких изменений.,
Это также может быть транзакционной проблемой, но в моем случае это было то, что ключ (в Oracle Database) в запросе на удаление имел тип данных CHAR (8) в базе данных, в этом случае, как вы можете найти в документации Oracle CHAR по сравнению с VARCHAR2, если ваши данные не имеют длины 8, остальные покрыты пробелом, а в JPA DELETE делается различие между "0001" и "0001".
Я пишу этот ответ, потому что я не вижу ничего подобного во всех моих исследованиях, и кто-то еще мог пройти через этот пост и иметь ту же проблему.
Приветствия.
Ответ 5
У меня была такая же проблема с сущностью, которая имеет много отношений. Что я сделал, так это установил обнуление родительских сущностей, произвел слияние, затем сделал сброс и очистку и, наконец, получил сущность снова, используя find и remove. Например:
objAgreement.setParent(null);
em.merge(objAgreement);
em.flush();
em.clear();
objAgreement= em.find(Agreement.class, objAgreement.getId())
em.remove(objAgreement);