Можно ли добавить "ON DELETE CASCADE" в таблицы, управляемые Hibernate?

У меня есть несколько таблиц, управляемых Hibernate с различными ограничениями внешнего ключа. Cascade on delete в настоящее время управляется только Hibernate. Для игры с тестовыми данными я часто создаю и удаляю несколько строк вручную. Это очень помогло бы мне, если бы я мог добавить DELETE CASCADE к ограничениям внешнего ключа, но я не знаю, будет ли Hibernate работать над этим, потому что база данных удаляет файлы до того, как Hibernate делает.


Многие люди, похоже, концентрируются на DDL. Мое намерение не указывать Hibernate для создания DDL с SQL DELETE CASCADES. Я просто хочу знать, если это навредит, если я укажу ON DELETE CASCADE в базе данных дополнительно, чтобы иметь JPA cascade = CascadeType.REMOVE в аннотации ссылки, например, @ManyToOne.

Ответ 1

Вы можете использовать CascadeType.DELETE, однако эта аннотация применяется только к объектам в EntityManager, а не к базе данных. Вы хотите быть уверенным, что ON DELETE CASCADE добавляется к ограничению базы данных. Чтобы проверить, вы можете настроить JPA для создания файла ddl. Взгляните на файл ddl, вы заметите, что ON DELETE CASCADE не является частью ограничения. Добавьте ON DELETE CASCADE в фактический SQL в файле ddl, затем обновите схему базы данных из ddl. Это устранит вашу проблему.

Эта ссылка показывает, как использовать ON DELETE CASCADE on для CONSTRAINT в MySQL. Вы делаете это по ограничению. Вы также можете сделать это в инструкции CREATE TABLE или ALTER TABLE. Вероятно, JPA создает ограничение в выражении ALTER TABLE. Просто добавьте ON DELETE CASCADE к этому утверждению.

Обратите внимание, что некоторые разработчики JPA предоставляют средства для этой функции.

Hibernate выполняет эту функцию с помощью аннотации @OnDelete, поэтому рекомендуется использовать это или просто обновлять файл ddl, если вы хотите придерживаться стандартных функций JPA.

Ответ 2

Я вижу две потенциальные проблемы:

  • Если объект, который представляет таблицу, в которую вы каскадируете операции непосредственно в базе данных, версируется, то это не сработает, потому что, когда Hibernate пытается самостоятельно удалить записи, проверка версии завершится неудачно (Hibernate будет принимать одновременный поток уже обновлены или удалены соответствующие записи).
  • Если существуют случаи, когда ваша бизнес-логика повторно сохраняет такие экземпляры сущности после того, как удаление было каскадировано для них из родителя (например, вы удаляете старый родительский объект и переносите ассоциированные дочерние элементы в новый, хотя лучше я бы вообще не каскадировал удаление, если такой вариант использования существует для ассоциации, но это зависит от вас, как это допускается спецификацией JPA), тогда Hibernate просто un-schedule удаление дочерних элементов и удаление только родительского элемента, поэтому вы по-прежнему будете иметь удаленные дочерние элементы, если вы каскадируете удаление в базе данных.

Возможно, в некоторых сценариях могут возникнуть проблемы, поэтому я бы рекомендовал не делать это.

Ответ 3

Вы можете использовать собственную базу данных для удаления дочерних записей при удалении родительской записи.

Помните о двунаправленных отношениях и, конечно же, убедитесь, что вы просто указали вставку и обновление в каскаде (чтобы быть на более безопасной стороне).

Ответ 4

Вы упомянули для целей тестирования. Я догадываюсь, выполняю некоторые тесты, удаляю данные, тестирую повтор...

При использовании кэширования второго уровня или кеша запросов кеш будет истек, если вы сразу удалите данные из базы данных. Это может привести к неожиданным результатам тестирования.

Итак, это будет противоречить Hibernate, если вы используете кэширование второго уровня/запроса, поскольку сущность не будет выведена из кеша. Убедитесь, что все кэши очищаются после того, как вы удалили данные напрямую. См. этот вопрос о том, как очистить кеш.

В официальном Hibernate docs также упоминается следующее:

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

Ответ 5

Используйте предложение orphanRemoval = true в вашем отношении @OneToMany. Затем, когда основная сущность (ParameterGroup) удаляется, каждая связанная запись (Параметр) сначала удаляется. Просто удалите объект ParameterGroup через entityManager. Также не забудьте установить предложение cascade как CascadeType.ALL (поддерживать все каскадные операции) или CascadeType.REMOVE (только для каскадного удаления).

@Entity
@Table(name = "PARAMETER_GROUP")
public class ParameterGroup {

    @Id
    private Long id;

    @OneToMany(mappedBy = "parameterGroup", fetch = FetchType.LAZY, cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Parameter> parameters = new LinkedList<>();

}

@Entity
@Table(name = "PARAMETER")
public class Parameter {

    @Id
    private Long id;

    @ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.REFRESH)
    @JoinColumn(name = "PARAMETER_GROUP_ID")
    private ParameterGroup parameterGroup;

}

Из документации:

public abstract boolean orphanRemoval (Optional)

Использовать операцию удаления для объектов, которые были удаляется из отношения и каскадирует операцию удаления на эти объекты.

Ответ 6

Не использовать cascade = CascadeType.REMOVE Документация здесь

Из-за вашего db может быть уничтожен. Вы можете использовать официальный заказ. Удалить sub stable и затем удалите главную таблицу