0

如果我问得不好,我很抱歉。我有一个带有模型(简化)的 Rails 3.1 应用程序,如下所示:

class Employee < ActiveRecord::Base
  has_many    :merged_children, :class_name => 'Employee', :foreign_key => "merge_parent_id"
  has_many    :timesheets

  def total_time 
    merged_children.timesheets.in_range(range).hours_minutes.sum 
  end
end

class Timesheet < ActiveRecord::Base
  belongs_to :employee

  def in_range(range)
    # filter records based on transaction_date in range 
  end

  def hours_minutes
    (hours + minutes/60.0).to_f
  end
end

注意:in_range 方法本质上是一个范围,而 hours_minutes 是一个计算。hours_minutes 对结果数据集中的每个时间表记录都有效,然后 total_time 应将这些值相加并返回金额。

“total_time”方法不起作用,因为employee.merged_children 返回一个数组,而timesheets 旨在针对单个Employee 对象运行。

有没有办法构造“total_time”,以便它仍然向数据库发送一个查询?迭代 merge_children 数组似乎不优雅,为每个数组发出查询。不确定直接调用 Arel 表是否会有所帮助或伤害,但我对想法持开放态度。

如果我们做对了,生成的 SQL 应该看起来像这样:

SELECT sum(hours + minutes/60.0)
FROM employees e1 join employees e2 on e1.id = e2.merge_parent_id join timesheets t on t.employee_id = e2.id
WHERE e1.id = [@employee.id] and t.transaction_date BETWEEN [@range.begin] and [@range.end]

非常感谢!

4

2 回答 2

0

这里最简单的可能是添加

has_many :children_timesheets, :through => :merged_children, :source => :timesheets

对于您的员工模型,

然后(假设 in_range 实际上是一个作用域,或者是一个进行查找的类方法)

children_timesheets.in_range(...)

应该是您感兴趣的时间表集合,您可以执行类似的操作

children_timesheets.in_range(...).collect(&:hours_minutes).sum
于 2011-12-21T08:25:54.480 回答
0

未经实际数据测试。

  range = ((1.day.ago)...(2.days.ago))
  merge_parent = Employee.find(some_id)

  Timesheet.where(:transaction_date => range)
     .joins(:employee).where(:employees => {:merge_parent_id => merge_parent.id})
     .sum('hours*60 + minutes')

   (0.3ms)  SELECT SUM(hours*60 + minutes) AS sum_id FROM "timesheets" INNER JOIN "employees" ON "employees"."id" = "timesheets"."employee_id" WHERE "employees"."merge_parent_id" = 1 AND ("timesheets"."created_at" >= '2011-12-13 03:04:35.085416' AND "timesheets"."created_at" < '2011-12-12 03:04:

为我返回“0”。所以希望它会给你带来更好的回报

于 2011-12-14T03:23:21.600 回答