ruby-on-rails - 寻求关于优化 ActiveRecord::destroy_all 的建议
问题描述
导轨 5+
我知道destroy_all
实例化每个模型并destroy
在其上运行并且delete_all
速度更快,但删除不尊重:
before_destroy
,around_destroy
和after_destroy
回调dependent
关系设置
假设该列表是全面的,我们是否应该destroy_all
通过检查模型的这些属性来节省时间,如果没有回调,只需根据需要处理关系吗?
编辑:我正在寻找一种修改默认destroy_all
行为的方法,使其更智能,并且不会盲目地实例化所有对象并链接到依赖关系的调用。如果我们有 A 与依赖 B (1:1) 的关系,并且 A 很大(1 百万),那么需要实例化和销毁很多对象。是的,应用程序/领域特定知识意味着您可以调用delete_all
,但如果有人更改模型并添加关系,那将delete_all
变得非常危险。如果我们进行优化destroy_all
以进行一些思考,我们可以将简单的关系从关系 A 上的单个调用(A 和 B)减少dependent: delete
到两个调用(A 和 B) ,其中原始将是 200 万个对象实例化和 DB 命中。delete_all
destroy_all
destroy_all
# Pseudocode
# Let the model in question be `User`
ids = self.pluck(:id)
if model.has_destroy_callbacks # I imagine there's some fancy introspection stuff I can use
original_destroy_all
return
else
# Check Restrict type
model.restrict_relationships.each do |rel|
other_models = some_cute_query
raise_exception_or_add_error if other_models.any?
end
# Add some check here to make sure we didn't miss any unknown dependency type
# Normal relationships
model.non_restrict_relationships.each do |rel|
dep_type = rel.dependent_type
if dep_type == :destroy
rel.where(model_id: ids).destroy_all
elsif dep_type == :delete
rel.where(model_id: ids).delete_all
elsif dep_type == :nullify
rel.where(model_id: ids).update_all(model_name_id: nil)
end
end
end
self.delete_all # i.e. the collection that was gonna get destroyed
我正在寻找的是健全性检查,如果我遗漏了一些明显的东西,为什么这不起作用。我也在寻找有关如何将其放入 ActiveRecord 的建议。另外,您可以专门覆盖destroy_all
特定模型上的集合/关系吗?
解决方案
The callback chain is accessible via the
_*_callbacks
method on an object. Active Model Callbacks support:before
,:after
and:around
as values for the kind property. The kind property defines what part of the chain the callback runs in.To find all callbacks in the before_save callback chain:
Topic._save_callbacks.select { |cb| cb.kind.eql?(:before) }
So in this case its _destroy_callbacks
but I would make the method raise an exception and bail instead of calling destroy_all
if your goal is a sanity check.
raise SomeKindOfError if model._destroy_callbacks.any?
That's far more helpful in terms of debugging and usage instead of just burying the problem.
Getting all the associations of model can be done via .reflect_on_all_associations
which gives you AssocationReflection objects. From there you can get the options of the association.
But...
This reeks of "clever" code. When you get to the point where using destroy callbacks is a performance problem there are bigger problems then just choosing between delete_all
or destroy_all
and automatically choosing does not really address the problem at all.
推荐阅读
- linux - 如何从许多文件中删除包含特殊字符的字符串
- jsf - 在 Wildfly 上重新部署应用程序后,f:websocket 在 JSF 2.3 中停止工作
- c++ - 可以在里面“排序”功能
用于对二维字符数组进行排序? - git - 无法从 git 中取消跟踪大文件:.gitignore 文件,git rm --cached。不工作
- kubernetes - Kubernetes 持久化卷和持久化卷声称超出存储
- angular - 如何在 Angular 2 的 Ngx 图表中为折线图中显示的点设置不同的颜色?
- google-cloud-platform - 获取上传到云存储的对象的公共 URL
- amazon-web-services - cognito 登录页面给出无效响应
- excel - 根据 1 个单元格更改部分行的背景颜色
- sql - 如何在 Redshift 中获取函数参数大小?