Как пакетное удаление с помощью bulkUpdate
У меня есть общие настройки User / Role с таблицей соединений user_role. Я пытаюсь использовать Spring HibernateTemplate для массового удаления всех заблокированных пользователей, как это:
getHibernateTemplate().bulkUpdate("delete from User where locked=?", true);
Если удаляемый пользователь не имеет никаких ролей (нет записи в таблице user_role), то все идет хорошо; Однако, если у пользователя есть запись роли, я получаю следующую ошибку:
нарушение целостности - найдена дочерняя запись
Роли определены в User.java следующим образом:
@ManyToMany(fetch = FetchType.EAGER)
@JoinTable(name = "user_role", joinColumns = { @JoinColumn(name = "user_id") }, inverseJoinColumns = @JoinColumn(name = "role_id"))
private Set<Role> roles = new HashSet<Role>();
Итак, как я могу пакетно удалить пользователей, даже если у пользователя есть дочерние записи? Спасибо!
4 ответа
Операции массового удаления не каскадируются к связанным объектам согласно спецификации JPA:
4.10 Операции массового обновления и удаления
Операции массового обновления и удаления применяются к объектам одного класса объектов (вместе с его подклассами, если таковые имеются). В предложении FROM или UPDATE может быть указан только один тип абстрактной схемы сущности.
...
Операция удаления применяется только к объектам указанного класса и его подклассов. Он не распространяется на связанные объекты.
Тем не менее, я ожидаю, что провайдер JPA будет иметь дело с таблицами соединения. К сожалению, Hibernate нет, и это вошло в HHH-1917. Боюсь, вам придется прибегнуть к нативному SQL, чтобы самостоятельно очистить таблицу соединений или использовать каскадные внешние ключи в схеме.
Каскадирование на уровне приложения (каскадирование через аннотации в спящем режиме или аннотации JPA) работает только в том случае, если фактическая сущность фактически загружена из БД. Когда вы используете шаблон hibernate с HQL, вы заметите, что сущности не загружены, и HQL напрямую преобразуется в SQL для выполнения.
Если вы хотите групповое удаление, вы должны использовать HQL-запрос для удаления всех соответствующих таблиц (т.е. ролей) перед удалением данных родительской таблицы.
Так как вы хотите массово удалить что-то, что имеет элементы, связанные с ManyToMany, вы должны сначала удалить отношение (в таблице соединений) или выполнить цикл и для каждого элемента удалить вручную (безумно и слишком тяжело).
Таким образом, поскольку JPQL не позволяет это сделать, возможный способ - сделать собственный запрос SQL для удаления нужного идентификатора в связанной таблице, а затем выполнить массовое удаление.
Я не совсем уверен, потому что мне трудно воссоздать эту проблему, но я думаю, что вам может понадобиться добавить каскад к вашему @ManyToMany
@ManyToMany(cascade = CascadeType.ALL)