销毁和删除的区别
Posted
技术标签:
【中文标题】销毁和删除的区别【英文标题】:Difference between Destroy and Delete 【发布时间】:2014-05-10 13:10:03 【问题描述】:有什么区别
@model.destroy
和@model.delete
例如:
Model.find_by(col: "foo").destroy_all
//and
Model.find_by(col: "foo").delete_all
我使用一个或另一个真的很重要吗?
【问题讨论】:
【参考方案1】:基本上“删除”直接向数据库发送查询以删除记录。在这种情况下,Rails 不知道它正在删除的记录中有哪些属性,也不知道是否有任何回调(例如 before_destroy
)。
“destroy”方法获取传递的 id,使用“find”方法从数据库中获取模型,然后对其调用 destroy。这意味着回调被触发。
如果您不希望触发回调或希望获得更好的性能,您可能需要使用“删除”。否则(大部分时间)你会想要使用“destroy”。
【讨论】:
【参考方案2】:是的,这两种方法有很大区别 如果您希望在不调用模型回调的情况下快速删除记录,请使用 delete_all
如果您关心模型回调,请使用 destroy_all
来自官方文档
http://apidock.com/rails/ActiveRecord/Base/destroy_all/class
destroy_all(conditions = nil) public
通过实例化每条记录来销毁匹配条件的记录 并调用它的destroy方法。执行每个对象的回调 (包括:依赖关联选项和 before_destroy/after_destroy 观察者方法)。返回集合 被毁坏的物品;每个都将被冻结,以反映 不应进行任何更改(因为它们无法持久化)。
注意:每条记录的实例化、回调执行和删除 一次删除多条记录时可能会很耗时。它 每条记录至少生成一个 SQL DELETE 查询(或者可能更多, 强制执行您的回调)。如果你想快速删除很多行, 不用担心它们的关联或回调,使用 delete_all 而是。
【讨论】:
【参考方案3】:当您在 ActiveRecord
对象上调用 destroy
或 destroy_all
时,将启动 ActiveRecord
'destruction' 过程,它会分析您要删除的类,确定它应该对依赖项执行什么操作,然后运行通过验证等。
当您在对象上调用delete
或delete_all
时,ActiveRecord
仅尝试对数据库运行DELETE FROM tablename WHERE conditions
查询,不执行其他ActiveRecord
级别的任务。
【讨论】:
【参考方案4】:基本上destroy
会在模型上运行任何回调,而delete
不会。
来自Rails API:
ActiveRecord::Persistence.delete
删除数据库中的记录并冻结此实例以反映不应进行任何更改(因为它们无法持久化)。返回冻结的实例。
在记录的主键上使用 SQL DELETE 语句简单地删除该行,并且不执行任何回调。
要强制执行对象的 before_destroy 和 after_destroy 回调或任何 :dependent 关联选项,请使用 #destroy。
ActiveRecord::Persistence.destroy
删除数据库中的记录并冻结此实例以反映不应进行任何更改(因为它们无法持久化)。
有一系列与销毁相关的回调。如果 before_destroy 回调返回 false,则取消操作并且 destroy 返回 false。有关详细信息,请参阅 ActiveRecord::Callbacks。
【讨论】:
您好@user740584 - 感谢您的回答。 “在模型上运行任何回调”是什么意思? @BKSpureon 他的意思是 ActiveRecord::Callbacks:api.rubyonrails.org/classes/ActiveRecord/Callbacks.html。一个这样的回调是model#before_destroy
,它可用于在某些条件下停止最终的destroy()
调用。【参考方案5】:
delete
只会从 db 中删除当前对象记录,但不会从 db 中删除其关联的子记录。
destroy
将从 db 中删除当前对象记录以及从 db 中关联的子记录。
它们的使用真的很重要:
如果您的多个父对象共享公共子对象,则在特定父对象上调用destroy
将删除在其他多个父对象之间共享的子对象。
【讨论】:
出色的答案。谢谢。我要补充一点,据我所知,术语是孩子们被“杀死”。残忍的杀婴。 在生产环境中的大多数情况下,您都希望使用 'destroy' 不,这没有必要。 我认为您应该为destroy
使用的词是 descendants,而不是 children:根据文档,destroy “创建一个新的从属性中提取对象,然后对其调用destroy。” rubydoc.info/docs/rails/4.1.7/ActiveRecord%2FRelation:destroy【参考方案6】:
已经有很多答案了;想继续前进。
docs:
对于 has_many,destroy 和 destroy_all 将始终调用要删除的记录的 destroy 方法,以便运行回调。但是 delete 和 delete_all 将根据 :dependent 选项指定的策略进行删除,或者如果没有给出 :dependent 选项,那么它将遵循默认策略。默认策略是什么都不做(保留设置了父 id 的外键),除了 has_many :through,默认策略是 delete_all(删除连接记录,不运行它们的回调)。
delete
措辞对ActiveRecord::Association.has_many
和ActiveRecord::Base
的作用不同。对于后者,删除将执行SQL DELETE
并绕过所有验证/回调。前者将根据传递给关联的:dependent
选项执行。但是,在测试过程中,我发现了以下副作用,即只为 delete
而不是 delete_all
运行回调
dependent: :destroy
示例:
class Parent < ApplicationRecord
has_many :children,
before_remove: -> (_) puts "before_remove callback" ,
dependent: :destroy
end
class Child < ApplicationRecord
belongs_to :parent
before_destroy -> puts "before_destroy callback"
end
> child.delete # Ran without callbacks
Child Destroy (99.6ms) DELETE FROM "children" WHERE "children"."id" = $1 [["id", 21]]
> parent.children.delete(other_child) # Ran with callbacks
before_remove callback
before_destroy callback
Child Destroy (0.4ms) DELETE FROM "children" WHERE "children"."id" = $1 [["id", 22]]
> parent.children.delete_all # Ran without callbacks
Child Destroy (1.0ms) DELETE FROM "children" WHERE "children"."parent_id" = $1 [["parent_id", 1]]
【讨论】:
【参考方案7】:例子:
Class User
has_many :contents, dependent: :destroy
end
user = User.last
user.delete -> only user
user.destroy -> delete user , and contents of user
delete
将从数据库中删除当前记录(无回调)
destroy
将删除当前记录和关联记录(有回调)
delete_all
和 destroy_all
也一样
【讨论】:
以上是关于销毁和删除的区别的主要内容,如果未能解决你的问题,请参考以下文章