【问题标题】:Is it possible to use a condition with count on a has_many relation?是否可以在 has_many 关系上使用 count 条件?
【发布时间】:2012-04-06 01:50:27
【问题描述】:

我有一个项目列表,想只显示有任务的项目。是否可以在 has_many 关系上使用 count 条件?

# get my project list
Project.includes(:tasks).where(...)

class Project < ActiveRecord::Base
  has_many :tasks

class Task < ActiveRecord::Base
  belongs_to :project

目前我正在通过循环执行此操作,但我认为这不是正确的方法。

【问题讨论】:

  • 我问过类似的问题here。希望对你也有帮助。

标签: ruby-on-rails ruby-on-rails-3 associations conditional-statements


【解决方案1】:

includes 指令通常指示简单地预先加载这些关联,而不是在数据库方面 JOIN 它们,因此如果没有一些额外的工作,您实际上无法在此处执行条件。

一种可以很好扩展的方法是使用关联的counter_cache 功能,这样您就可以始终对任务数进行计数。您甚至可以在这些上添加索引以进一步提高查询的性能。

另一种方法是尝试从tasks 表向后工作,可能像:

Project.where('id IN (SELECT DISTINCT project_id FROM tasks)')

大概您在tasks 表中的project_id 上有一个索引,以使该操作相当便宜。

【讨论】:

  • 你不需要counter_cache。由于使用了includes 指令,因此生成的底层SQL 使用LEFT OUTER JOIN。这是进行非空检查的问题。如果用户使用joins,场景会简单得多。我在下面的回答中讨论了这个问题。
  • 我认为最好不要加载不需要的东西。如果一个项目有十亿个任务,毫无限制地加载它们可能会破坏应用程序。
  • 我明白,这是在选择急切加载时必须采取的一般预防措施。
【解决方案2】:

如果问题像标题所暗示的那样简单,不知道为什么这不起作用:

Project.joins(:tasks)

除非另有说明,否则联接将是内部联接,因此会排除项目没有任务的任何结果,所以也许这就是您所需要的……如果您想显示 所有 项目有任务。

如果您有某些条件(例如,状态为活动的项目),您还可以指定类似的条件

Project.joins(:tasks).where("status = 'active')

还是我错过了什么?

【讨论】:

    【解决方案3】:

    由于您已经迫不及待地加载项目的任务,您可以使用以下语句来获取带有任务的项目。

    # get my project list
    Project.includes(:tasks).where("tasks.id IS NOT NULL")
    

    这是因为includes 使用LEFT OUTER JOIN

    另一方面,如果您不想急切加载任务,则可以使用 joins,因为它使用 INNER JOIN。

    Project.joins(:tasks).where(...)
    

    【讨论】:

      猜你喜欢
      • 2021-09-02
      • 2010-11-26
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      • 2016-03-07
      • 1970-01-01
      • 1970-01-01
      • 2012-10-05
      相关资源
      最近更新 更多