Ruby on rails 3 Rails:如何判断一条记录在其任何一个子表中是否有子记录?
我在Rails 3中工作,有一个包含多个子表的表,例如Ruby on rails 3 Rails:如何判断一条记录在其任何一个子表中是否有子记录?,ruby-on-rails-3,rails-activerecord,Ruby On Rails 3,Rails Activerecord,我在Rails 3中工作,有一个包含多个子表的表,例如 class Foo < ActiveRecord::Base has_many :things has_many :items has_many :widgets end class Thing < ActiveRecord::Base belongs_to :foo end class Item < ActiveRecord::Base belongs_to :foo end class Wid
class Foo < ActiveRecord::Base
has_many :things
has_many :items
has_many :widgets
end
class Thing < ActiveRecord::Base
belongs_to :foo
end
class Item < ActiveRecord::Base
belongs_to :foo
end
class Widget < ActiveRecord::Base
belongs_to :foo
end
好吧,我认为你的思路是对的,但也许只是把它作为一种方法放在你的Foo模型中
class Foo < ActiveRecord::Base
def children?
things.any? || items.any? || widgets.any?
end
end
class Foo
然后只要说,
Foo.first.children?
并获得true
,如果Foo实例有任何子实例。您可以将Thing Item和Widget子类化。或者添加一个多态联接表来跟踪它。不太理想,我知道
你至少可以这样做,这样读起来会好一点
if foo.things.exists? || foo.items.exists? || foo.widgets.exists?
puts "This foo is in use!"
end
“空的?”我相信是在幕后使用“存在的”。这就是
any?
的用途
class Foo < ActiveRecord::Base
def children?
things.any? || items.any? || widgets.any?
end
end
这里的要点是,在任何情况下,存在
进行DB调用,如果总是将空格
加载到内存中,则asany?
不会进行调用。正如我说过的,很多时候,重要的不是DB调用的效率(是的,SQL调用存在?
使得效率更高),而是any?
不一定会调用DB,这是一个巨大的优势。寻找你自己:
[20] pry(main)> Benchmark.measure { foo.item.exists? }
Item Exists (0.5ms) SELECT 1 AS one FROM "items" ...
=> #<Benchmark::Tms:0x007fc1f28a8638
@cstime=0.0,
@cutime=0.0,
@label="",
@real=0.002927,
@stime=0.0,
@total=0.00999999999999801,
@utime=0.00999999999999801>
[21] pry(main)> Benchmark.measure { foo.items.any? }
=> #<Benchmark::Tms:0x007fc1f29d1aa0
@cstime=0.0,
@cutime=0.0,
@label="",
@real=7.6e-05,
@stime=0.0,
@total=0.0,
@utime=0.0>
正如我所说,很多时候,这取决于环境——在很多情况下,这些项目可能不会加载到内存中,但很多时候,它们会加载到内存中。根据您的调用方式选择最适合您的关联。假设所有关联都加载到内存中:
class Foo < ActiveRecord::Base
has_many :things
has_many :items
has_many :widgets
def in_use?
[things, items, widgets].flatten.any?
end
end
更正确,并且已经在我之前提出。这应该适用于任何给定的模型
class Foo < ActiveRecord::Base
def children?
has_associated_records = self.class.reflect_on_all_associations.map { |a| self.send(a.name).any? }
has_associated_records.include?(true)
end
end
class Foo
我会使用any?
,因为present?
有一组不必要的字符串空检查,而且也不必要地检查[]
是否为nil
。注意:foo.things
将始终返回一个数组,尽管有时返回一个空数组。@veritas您仍然是错的-我认为您没有完全理解活动记录集合。他们并不是在所有情况下都急于加载。things不会总是返回数组。在任何情况下?还是存在?它不会加载ruby对象。任何是否计数并与比现有值慢的零进行比较?它只是在数据库中查找id。@Swards如果foo.things
没有返回数组,则表明您的AR关系设置错误、直接且简单。我鼓励你看看我更新的答案。你只是不理解这里的一些东西,或者浏览我的答案,或者其他什么。看看我的答案,看看我是否真的完全正确。@veritas-这正是我要说的:foo.things在某些情况下不返回数组(例如在附加“.exists?”时)。你可以自己确认——这可能会改变你的答案。这与将作用域附加到集合的方式非常相似。是否存在?将选择“1”,是否有?将执行选择计数(*)。任何在我的测试中慢了一点。没那么快。如果将任何事物
、项目
或小部件
加载到内存中,存在?
仍会对其中每一项执行查询<代码>有吗?没有。这取决于用例,但考虑到OP的问题,这些模型很可能会加载到内存中,因此any?
将更有效。它们不会加载到内存中。但重要的是,您必须使用exists?
对数据库进行>=1次调用,而使用any?
,您可以进行潜在的0次调用,并且通常比存在的次数要少得多(正如我所说,这取决于具体情况)。对数据库的调用比对内存的调用慢得多。“存在吗?”在mysql中生成一个sql“选择“1”,并测试是否找到任何结果“任何?”将执行“选择计数(*)”。它们都执行一个SQL调用和任何SQL调用?稍微慢一点。你自己试试。OP不会预加载收藏,然后测试是否存在。是的,我一直在说的。哦,nvm,我想你说的是如果OP不会预加载…
。OP从未指定,它很可能会根据情况预加载。任何涉及的内容都包括语句等。
> Benchmark.measure { 1000.times {foo.items.exists?} }.total
=> 2.5299999999999994
> Benchmark.measure { 1000.times {foo.items.any?} }.total
=> 0.0
class Foo < ActiveRecord::Base
has_many :things
has_many :items
has_many :widgets
def in_use?
[things, items, widgets].flatten.any?
end
end
things.any? || items.any? || widgets.any?
class Foo < ActiveRecord::Base
def children?
has_associated_records = self.class.reflect_on_all_associations.map { |a| self.send(a.name).any? }
has_associated_records.include?(true)
end
end