delete_all vs destroy_all?

146

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

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all
u.sources.destroy_all
u.user_stats.destroy_all
u.delete

Это работает и удаляет все ссылки пользователя из всех таблиц, но я слышал, что destroy_all был очень тяжелым процессом, поэтому я попробовал delete_all. Он удаляет пользователя только из собственной таблицы пользователя, а id из всех остальных таблиц имеет значение null, но оставляет записи в них нетронутыми. Может ли кто-нибудь поделиться, какой правильный процесс для выполнения такой задачи?

Я вижу, что destroy_all вызывает функцию destroy для всех связанных объектов, но я просто хочу подтвердить правильный подход.

Теги:
database
activerecord

4 ответа

191
Лучший ответ

Вы правы. Если вы хотите удалить пользователя и все связанные объекты → destroy_all Однако, если вы просто хотите удалить пользователя без подавления всех связанных объектов → delete_all

В соответствии с этим сообщением: Rails: dependent = > : destroy VS: depend = > : Delete_all

  • destroy/destroy_all: связанные объекты уничтожаются рядом с этим объектом, вызывая их метод destroy
  • delete/delete_all: все связанные объекты немедленно уничтожаются без вызова метода: destroy
  • 68
    Следует также отметить, что 1) delete_all не вызываются при использовании delete_all , и 2) destroy_all создает все записи и уничтожает их по одной за раз, поэтому при очень большом наборе данных это может быть мучительно медленным.
  • 0
    Предположим, я запускаю метод before_destroy в модели - если я использую delete_all, то этот метод не будет работать? во-вторых, если я использую метод before_delete в моей модели, будет ли он выполняться при запуске delete или delete_all в консоли rails?
18

delete_all - это один оператор SQL DELETE и ничего больше. destroy_all вызывает destroy() для всех соответствующих результатов: условий (если они есть), которые могут быть как минимум NUM_OF_RESULTS SQL-инструкций.

Если вам нужно сделать что-то серьезное, такое как destroy_all() на большом наборе данных, я бы, вероятно, не сделал этого из приложения и обрабатывал его вручную с осторожностью. Если набор данных достаточно мал, вы не пострадали бы.

16

Чтобы избежать того факта, что destroy_all создает все записи и уничтожает их по одному, вы можете использовать его непосредственно из класса модели.

Итак, вместо:

u = User.find_by_name('JohnBoy')
u.usage_indexes.destroy_all

Вы можете сделать:

u = User.find_by_name('JohnBoy')
UsageIndex.destroy_all "user_id = #{u.id}"

Результатом является один запрос на уничтожение всех связанных записей

  • 1
    Будет ли он вызывать обратные вызовы уничтожения для связанных записей, или UsageIndex.destroy_all эквивалентно UsageIntex.delete_all ?
1

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

Этот жемчуг добавляет новый параметр для ассоциаций ActiveRecord:

зависит:: delete_recursively

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

Обратите внимание, что так же, как depend:: delete или depend:: delete_all, эта новая опция не вызывает обратные вызовы зависимых записей around/before/after_destroy.

Однако возможно иметь зависимые:: уничтожать ассоциации в любой цепочке моделей, которые в противном случае связаны с зависимыми:: delete_recursively. Опция: destroy будет нормально работать в любом месте вверх или вниз по линии, создавая и уничтожая все соответствующие записи и тем самым также вызывая их обратные вызовы.

  • 0
    Это фантастика! Интересно, почему не так много людей смотрели / снимали / разветвляли его на github ... это все еще работает хорошо?
  • 0
    @Magne Спасибо! Это должно работать. Тесты работают на Ruby 2.4.1 и Rails 5.1.1. До сих пор я использовал его только в личных целях, а не в основных производственных приложениях, следовательно, в основной версии «0», но я никогда не замечал никаких проблем. Это также довольно просто, так что должно быть хорошо.
Показать ещё 2 комментария

Ещё вопросы

Сообщество Overcoder
Наверх
Меню