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
ассоциация дает ожидаемый результат: дочерние записи корректно удаляются без необходимости удаления родительской записи.
Жаль, что ошибка не записывается более четко.
Я получил ту же проблему, когда следующие вещи собрались вместе.
- Hibernate 3.6.10.Final
- Родительский объект без ссылки на Child.
Некоторая дочерняя сущность со ссылкой на Родителя. Это устаревший код.
class ChildEntity { @ManyToOne(cascade = CascadeType.ALL) private ParentEntity parent; }
Дочерняя сущность загружается в контекст сеанса, а затем удаляется из таблицы без уведомления JPA внутри транзакции (хранимая процедура, собственный sql)
Тогда родитель не может быть удален. Без удаления, без исключения, просто сообщение "не запланировать удаление" в журнале 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,...)