destroy_all在事务中不起作用,当我们在它前面放置where子句时



我遇到了意想不到的行为。当我在一个关系上调用destroy_all时,它通过一个ActiveRecord事务执行,但是当我在它之前放置一个where子句时,有一个意外的行为,每个记录都被单独销毁。

的例子:

Actor.find(1).movies.destroy_all这里destroy_all将在事务中运行,但是Actor.find(1).movies.where(id: [1,2,3]).destroy_all将单独执行每个销毁。

有解释吗?

这是因为你在处理不同的对象:

Actor.find(1).movies.class                    
# Movie::ActiveRecord_Associations_CollectionProxy
Actor.find(1).movies.where(id: [1,2,3]).class 
# Movie::ActiveRecord_AssociationRelation

两个类都以自己的方式定义了自己的delete_all方法:

# File activerecord/lib/active_record/associations/collection_proxy.rb
def destroy_all
@association.destroy_all.tap { reset_scope }
end
# File activerecord/lib/active_record/relation.rb
def destroy_all
records.each(&:destroy).tap { reset }
end

所以当你执行Actor.find(1).movies.destroy_all时,动作是通过在@association上调用destroy_all来处理的。

但是通过执行Actor.find(1).movies.where(id: [1,2,3]).destroy_all,每个对象都有一个迭代,对每个对象调用destroy

@association.delete_all被定义为获取一个ActiveRecord_Relation,并在单个事务中执行销毁包装它们的元素:

def destroy_all
destroy(load_target).tap do
reset
loaded!
end
end

通过尝试该方法,您可以得到与第一个示例相同的结果;

Actor.find(1).movies.instance_variable_get("@association").send(:destroy, Movie.all)

相关内容

  • 没有找到相关文章

最新更新