Sum returns 的值应该是 return 0

Sum returns value when should return 0

我遇到了一个非常令人困惑的问题。这是:

[12] pry(EstimatedTime)> EstimatedTime.where(user_id: User.current.id, plan_on: date).pluck(:hours) => [] 
[13] pry(EstimatedTime)> EstimatedTime.where(user_id: User.current.id, plan_on: date).sum(:hours) => 3.0

这是什么魔法?

此语句位于从视图调用的模型方法中。在此之前,在控制器操作中,我调用了同一模型的另一个方法,即在事务中执行批量创建记录。

def self.save_all(records)
  transaction do
    records.each do |record|
      record.save!
    end
  end
  rescue ActiveRecord::RecordInvalid
    return false 
end

正在抛出异常,方法 returns false,视图已呈现并发生这种情况。

UPD 我找到了一个解决方法,将 .sum 替换为 .pluck(:hours).sum,但我仍然不知道为什么我的第一种方法失败了。

正如 David Aldrige 在对该问题的评论中指出的那样,问题在于 .sum(:hours) 使用的是缓存数据,而 .pluck(:hours) 实际上是在查看数据库。

为什么数据库和查询缓存包含不同的数据?好吧,似乎在 Rails 3 中(我应该在提问时指定我的 rails 版本)失败的事务将回滚数据库,但保持查询缓存完好无损。这导致数据库和缓存之间的临时数据不一致。正如 this 问题中指出的那样,Rails 4 中对此进行了更正。

解决方案 1 也就是我为自己选择的解决方案

事务失败后清除查询缓存。因此,在事务中执行批量插入的方法现在如下所示:

def self.save_all(records)
  transaction do
    records.each do |record|
      record.save!
    end
  end
  rescue ActiveRecord::RecordInvalid
     self.connection.clear_query_cache
     return false 
end

解决方案 2

虽然我无法在性能方面比较这些解决方案,但我个人认为这不太优雅,所以我将 post 它们都用。可以像这样简单地写求和语句:

EstimatedTime.where(user_id: User.current.id, plan_on: date).pluck(:hours).sum

它会使用数据库数据计算总和,绕过缓存不一致的问题。