Rails:在has_many关系上使用inverse_of不会减少对数据库

时间:2015-11-22 00:35:49

标签: ruby-on-rails

在我的Ruby on Rails项目中,Course模型是这样的:

    class Course < ActiveRecord::Base
      has_many :teams, inverse_of: :course, dependent: :destroy

并且团队模型是这样的:

    class Team < ActiveRecord::Base
      belongs_to :course

当我执行以下if语句

时,I​​nverse_of应该可以帮助我阻止对数据库的查询
    if(tm.course == current_course) #tm is a team and current_course is a course
      return tm

我检查控制台输出,看到if语句仍然调用它:

    CACHE (0.0ms)  SELECT  `courses`.* FROM `courses` WHERE `courses`.`id` = 2 LIMIT 1  [["id", 2]]

有什么想法和建议吗?

1 个答案:

答案 0 :(得分:0)

这很好。该查询未再次访问数据库。 CACHE (0.0ms)来自Rails缓存,通常在内存中,除非您在应用配置中更改它。

修改

实际上,如果您想频繁访问关联对象,您可能还想添加include

has_many :teams, -> { includes :course }, inverse_of: :course, dependent: :destroy

这应该强制Rails在单个数据库访问中加载两个记录并将它们保存在缓存中。

另一个编辑

如果您想避免第二次交易,可以执行tm = Team.includes(:course).find params[:id]之类的操作。这样,当if发生时,查询将不需要新的事务。 相反,当你调用find时,你会看到两个SELECT一个接着一个接一个。我认为这是最好的。

inverse_of重要的一点是,tm.course.team的目的是不会触发Team上的第二次选择,而是注意.team引用tm并且只做两个选择而不是三个。

另一个编辑

请在rails console中尝试此操作。

打开Team.first.course.team

inverse_of,然后更改它,重新加载控制台并再次运行它。你会明白我的意思。

最终(HOPEFULLY)编辑

我会尝试详细解释this ......

prison = Prison.create(name: 'Bad House')

这将导致对表Prison的数据库进行SELECT。

criminal = prison.criminals.create(name: 'Krazy 8') 这将导致表Criminal中的INSERT,然后是SELECT以检索它并将其分配给变量criminal

如果我有inverse_of: :course,则意味着访问criminal.prison 不会导致另一个查询,因为criminal将“记住”他通过prison它将返回变量prison,而不是再次查询db。

在您的情况下......假设您正在创建tm,就像这样:

tm = Team.find param[:id]

无论您做什么,这都将导致访问数据库。

然后tm.course == current_course将需要第二个SELECT,这次是针对Course查找课程,因为到目前为止您还没有使用Course

然后,我们假设您这样做:

course = tm.course

然后copy_of_team = course.team。您可以在此处看到inverse_of的效果。

如果你想摆脱第二次选择,你必须使用tm = Team.includes(:course).find param[:id]。这当然仍然需要一个选择来检索课程信息,但它将在同一个数据库事务中发生,因此它比没有它更好。