Rails: 通过另一个外键过滤 has_many 关系

3

我想知道人们在通过其他外键过滤has_many关系的内容时偏好的方法。例如,假设您有三个实体:部门、员工和项目。一个部门拥有许多员工,一个项目也有许多员工。我有一个项目,我想从给定的部门获取所有它的员工。我的代码如下:

# department.rb

has_many :employees

# employee.rb

belongs_to :department
belongs_to :projects

# project.rb

has_many :employees

我可以想到四种解决我的问题的方法:

方法1:类查询方法:

# anywhere.rb

Employee.where(:project_id => project, :department_id => department)

方法二:辅助方法

# project.rb

def employees_from_department(department)
  employees.select { |emp| emp.department == department }
end

方法三:在关系上使用帮助方法

# project.rb

has_many :employees do
  def from_department(department)
    where(:department_id => department)
    # Could also be all.select { |emp| emp.department == deparment }
  end
end

方法4:作用域

# employee.rb

scope :from_department, lambda { |department|
  where(:department_id => department)
}

# anywhere.rb

project.employees.from_department(department)

我几乎总是选择 Approach #4,因为它最可重用。我可以将该范围应用于任何返回 Employees 的查询。我可以将其与其他作用域组合使用,设置排序等。此外,使用作用域意味着我所有的只读、查询式代码都命名相当一致,并且组织在顶部,所以我拥有更少的方法。作用域是我最喜欢的 Rails 功能之一。但我发现自己一直在编写它们,以至于我几乎有一个参数化的作用域来匹配每个 :belongs_to。这是正确的方法吗?另外,似乎我正在生成大量的数据库查询,所以我想知道是否我有可能破坏了 Rails 为我完成的任何缓存,因为我的作用域每次都强制 Rails 前往数据库。

在某种程度上这是一个性能问题,这意味着没有一个大小适合所有的答案,你需要测试代码在生产中找到正确的方式。但在你的代码进入生产之前,你倾向于选择哪种方法?或者还有其他方法吗?


#1和#3应生成相同的SQL(除非您在#3中使用all.select)。至于#4,project在哪里?不要使用#2,它会检索过多的数据,在这种情况下,employees.find(:all,:conditions => ...).find_by_...或可能是where更好。 - Victor Moroz
@Victor:我修改了第四个代码,以展示作用域的使用。 - Paul A Jungwirth
2个回答

2
我个人更喜欢作用域(方法4)或类方法。
我认为在一般情况下,如果您使用链式作用域,您的方法4和方法1应该生成相同的SQL语句,例如:
project.employees.from_department(department_id)

您可以在控制台中尝试添加.to_sql调用,以查看实际生成的SQL。
为了进行性能(SQL)分析,您可以使用诸如query-reviewerrack-bug之类的工具,这些工具非常方便和有用。

我同意 #1 和 #4 应该生成相同的 SQL。感谢提供 SQL 分析工具的链接! - Paul A Jungwirth

1
project.employees.find_by_department_id(department)

(基本上与#3相同)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接