Rails: удалить каскад против зависимого уничтожения

Предполагая, что у меня есть две таблицы: users а также orders, У пользователя много заказов, поэтому, естественно, в моей таблице заказов есть внешний ключ user_id.

Какова наилучшая практика в рельсах (с точки зрения скорости, стиля и ссылочной целостности), чтобы гарантировать, что, если пользователь будет удален, все зависимые заказы также будут удалены? Я рассматриваю следующие варианты:

Случай 1. Использование :dependent => :destroy в пользовательской модели

Случай 2. Определение таблицы заказов в postgres и записи

user_id integer REFERENCES users(id) ON DELETE CASCADE

Есть ли какая-то причина, почему я должен использовать Случай 1? Кажется, дело 2 делает все, что я хочу? Есть ли разница в скорости исполнения?

3 ответа

Решение

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

В младенчестве приложения я бы порекомендовал :dependent => :destroy потому что это позволяет вам развиваться таким образом, который не зависит от базы данных. Как только вы начнете масштабироваться, вы должны начать делать это в базе данных по соображениям производительности / целостности.

has_many :orders, dependent: :destroy

  • Самый безопасный вариант для автоматического поддержания целостности данных.
  • У вас есть полиморфные ассоциации, и вы не хотите использовать триггеры.


add_foreign_key :orders, :users, on_delete: :cascade (в миграции базы данных)

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


has_many :orders, dependent: :delete_all

  • Используйте только в том случае, если has_many является листовым узлом в дереве ассоциации (т. Е. У дочернего элемента нет другой ассоциации has_many со ссылками на внешний ключ)

Я бы использовал вариант 1. Хотя он может работать, я вижу ряд проблем с вариантом 2:

  1. ActiveRecord не будет знать, что эти записи были удалены, что может привести к нестабильному поведению
  2. всем, кто читает код, будет неясно, что удаление пользователя означает, что все его заказы также будут удалены
  3. любой destroy обработчики на ордене не стреляют

Конечно, я ожидал бы, что вариант 2 будет быстрее, но это зависит от вас, если компромиссы того стоят. Является ли удаление пользователя обычной операцией в вашем приложении?

Другой вариант будет использовать :dependent => :delete_all, Это было бы быстрее, чем :dependent => :destroy и избегайте недостатков 1 и 2 выше. Смотрите здесь для более подробной информации.

Другие вопросы по тегам