gpt4 book ai didi

ruby-on-rails - 在 Rails 中没有其他查询的情况下限制急切加载 `where`

转载 作者:行者123 更新时间:2023-12-02 03:57:17 25 4
gpt4 key购买 nike

A有很多B,B有很多C。 C 有一个名为 thing 的属性:

class A < ActiveRecord::Base
has_many :bs
end
class B < ActiveRecord::Base
belongs_to :a
has_many :cs
end
class C < ActiveRecord::Base
belongs_to :b
attr_accessible :thing
end

我想查询属于 A 的所有 B,并急切地加载属于所述 B 的 C:

> a = A.first
A Load (0.2ms) SELECT "as".* FROM "as" LIMIT 1
=> #<A id: 1, created_at: "2012-08-21 09:25:18", updated_at: "2012-08-21 09:25:18">
> bs = a.bs.includes(:cs)
B Load (0.2ms) SELECT "bs".* FROM "bs" WHERE "bs"."a_id" = 1
C Load (0.1ms) SELECT "cs".* FROM "cs" WHERE "cs"."b_id" IN (1)
=> [#<B id: 1, a_id: 1, created_at: "2012-08-21 09:25:22", updated_at: "2012-08-21 09:25:22", thing: nil>]
>

这很好用:

> bs[0]
=> #<B id: 1, a_id: 1, created_at: "2012-08-21 09:25:22", updated_at: "2012-08-21 09:25:22", thing: nil>
> bs[0].cs
=> [#<C id: 1, b_id: 1, thing: 2, created_at: "2012-08-21 09:29:31", updated_at: "2012-08-21 09:29:31">]
>

——但不是在我想稍后对属于 B 实例的 C 执行 where() 搜索的情况下:

> bs[0].cs.where(:thing => 1)
C Load (0.2ms) SELECT "cs".* FROM "cs" WHERE "cs"."b_id" = 1 AND "cs"."thing" = 1
=> []
> bs[0].cs.where(:thing => 2)
C Load (0.2ms) SELECT "cs".* FROM "cs" WHERE "cs"."b_id" = 1 AND "cs"."thing" = 2
=> [#<C id: 1, b_id: 1, thing: 2, created_at: "2012-08-21 09:29:31", updated_at: "2012-08-21 09:29:31">]
>

请注意,尽管我们拥有可用信息,但仍会重新发出查询。

当然,我可以只使用Enumerable#select:

> bs[0].cs.select {|c| c.thing == 2}
=> [#<C id: 1, b_id: 1, thing: 2, created_at: "2012-08-21 09:29:31", updated_at: "2012-08-21 09:29:31">]
>

这避免了重新查询,但我有点希望 Rails 可以自己做类似的事情。

真正的缺点是我想在我们不知道关联是否被急切加载的地方使用这段代码。如果没有,则 select 方法将在执行筛选之前为 B 加载所有 C,而 where 方法将生成 SQL 以获取较小的数据集。

我根本不相信这很重要,但如果我在预加载方面遗漏了什么,我很乐意听到。

最佳答案

我认为您没有遗漏任何东西。我不相信事件记录可以做任何聪明的事情——而且我认为很难可靠地做到这一点。就像你说的,它必须确定你是否已经预先加载了关联,但它也必须猜测循环 Cs 的内存集合是否会更快(如果它是一个小的集合)或者去数据库一次获取所有合适的 C 是否会更快(如果它是一个非常大的集合)。

在您的情况下,最好的办法可能是将默认范围设置为始终 预加载 cs,甚至可以编写您自己的奇特方法来按事物获取它们。可能是这样的:

class B < ActiveRecord::Base
belongs_to :a
has_many :cs
default_scope includes(:cs)

def cs_by_thing(thing)
cs.select{|c|c.thing == thing}
end
end

然后你总是可以知道在查询你的 cs 时你永远不会回到数据库:

a = A.first
[db access]
a.bs.first
[db access]
a.bs.first.cs
a.bs.first.cs_by_thing(1)
a.bs.first.cs_by_thing(2)

关于ruby-on-rails - 在 Rails 中没有其他查询的情况下限制急切加载 `where`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12051996/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com