使用 ActiveRecord 助手删除 VS 查找孤儿
问题:使用 ActiveRecord 助手删除 VS 查找孤儿 我正在尝试删除不再有任何users的所有organizations。 使用下面的代码,我可以找到我想要删除的所有记录: Organization.includes(:users) .where(users: { id: nil }) .references(:users) 当我添加delete_all时,如果我不包含reference
问题:使用 ActiveRecord 助手删除 VS 查找孤儿
我正在尝试删除不再有任何users
的所有organizations
。
使用下面的代码,我可以找到我想要删除的所有记录:
Organization.includes(:users)
.where(users: { id: nil })
.references(:users)
当我添加delete_all
时,如果我不包含references
,我会得到同样的错误:
PG::UndefinedTable: ERROR: missing FROM-clause entry for table "users"
我可能可以用纯 SQL 编写解决方案,但我不明白为什么当我添加delete_all
语句时 Rails 没有保留对users
的引用。
以下是更多细节:
Organization:
has_many :users
User:
belongs_to :organization
解答
我发现includes
仅对急切加载有用(它可以很少处理我的情况),并且当与references
结合使用时,它会生成完全疯狂的东西(用tN_rM
之类的东西为每个字段别名)甚至虽然它实际上做了一个LEFT OUTER JOIN
...如果它没有在delete_all
出现后消失,那它_可以_帮助!
我发现仅仅使用exists
就更清晰、更简单了。它是 Arel(避免它是没有意义的,它无论如何都在 ActiveRecord 的引擎盖下),但它是如此之小,以至于它几乎不引人注意:
Organization.where(
User.where('users.organization_id = organizations.id').exists.not
)
或者,如果这个 SQL 字符串对您来说不好看,请使用更多的 Arel,这样它就会变得明显:
Organization.where(
User.where(organization_id: Organization.arel_table[:id]).exists.not
) # I tend to extract these ^^^^^^^^^^^^^^^^^^^^^^^ into local variables
这可以很好地处理将.delete_all
链接到顶部,因为它不是(在语法上)连接,即使它实际上等效于一个。
这背后的魔力
SQL 有一个EXISTS
运算符,它在功能上类似于连接,除了无法从连接表中选择字段。它形成一个有效的布尔表达式,可以否定和扔到WHERE
-conditions 中。
在“无 SQL”形式中,我使用了一个表达式“表的列”,结果证明它可以在 Rails 的哈希条件中使用。这是一个偶然的发现,是 Arel 为数不多的不会使代码变得过于庞大的用途之一。
更多推荐
所有评论(0)