【问题标题】:ActiveRecord - pre fetch single records from associationActiveRecord - 从关联中预取单个记录
【发布时间】:2011-04-30 21:04:42
【问题描述】:

考虑以下模型..

class Product < ActiveRecord::Base
  has_many    :pricings
end

class Pricing < ActiveRecord::Base
  belongs_to  :server
end

定价是产品价格的历史跟踪表,因此随着时间的推移可能会捕获数百个价格点。我想添加的是一种仅获取产品当前定价的方法。

虽然我可以向模型添加一个 has_one 关系,如下所示:

has_one  :current_pricing, :class_name => "Pricing", :foreign_key => "product_id",
         :order => 'created_at DESC'

这将获取当前产品的所有定价,然后仅返回第一条记录。

我正在寻找一种以更有效的方式完成此任务的方法,并希望有人能提供类似的意见或以前的经验。

【问题讨论】:

    标签: mysql ruby-on-rails sqlite activerecord


    【解决方案1】:

    您可以使用命名范围。将此放在定价模型的顶部:

    class Pricing < ActiveRecord::Base
      named_scope :current, lambda { |product| { :conditions => { :product_id => product.id }, :order => 'created_at DESC', :limit => 1 } }
    end
    

    然后要获取产品的当前定价,您可以调用“Pricing.current(product).first”。

    除了定价的命名范围之外,您还可以向 Product 模型添加一个访问器方法,如下所示:

    class Product < ActiveRecord::Base
      def current_pricing
        Pricing.current(self).first
      end
    end
    

    【讨论】:

    • 或者,您可以避免命名范围并将所有逻辑放在 Product#current_pricing 中,使用“Pricing.find(:first, :conditions => { :product_id => self.id }, : order => 'created_at DESC')。命名范围更加通用,因为它可以与其他查找器链接,但是如果您只需要这样,将所有逻辑放在 Product 中会更简单。
    • 我应该澄清一点 - 实际上我已经在产品类中省略了一个命名范围。我正在寻找一种通过包含或加入来执行此操作的方法,这样我就不必为返回的每个项目运行单独的查询。我以前在原始 SQL 中做过类似的事情,只是在 ActiveRecord 语法上有问题。
    • 我不明白你的意思。
    • 我需要一种方法来轻松查询产品的最新定价 - 我最终做的是使用您提供的范围并在定价类上创建一个 after_save 回调来更新 '产品上的 current_pricing_id'。使用该 ID,我添加了与产品对象的关联,我可以轻松地将其包含在查询中。另外,由于更新 id 是通过回调处理的,因此更新对用户来说非常透明。
    • 啊,现在我明白你的意思了。您可能可以使用复杂的连接和组查找器参数来完成此操作,但我认为您在产品表本身中缓存最新定价 ID 的解决方案可能是最好的——它极大地简化了代码并且在数据库方面更有效,这使它具有可扩展性(如果您担心的话)。
    【解决方案2】:

    您正在寻找一个 named_scope。在您的定价模型中定义它。为它提供 1 个参数,即 product_id。

    named_scope :latest_price, lambda { |*args| {:conditions => {:product_id => args.first}, :order => "created_at DESC", :limit => 1} }
    

    顺便说一句,非常棒的screencast

    【讨论】:

    • 这与我提出的解决方案基本相同,但是您的大括号未对齐-关闭 :conditions 哈希大括号在错误的位置
    • 我应该澄清一下 - 我希望通过包含或连接来执行此操作,以便限制正在运行的查询数量。
    • 糟糕!嘿,正如你所看到的,时间戳,正如他们所建议的,我们的帖子几乎同时上升。感谢您的提醒!
    【解决方案3】:

    在查询中添加 :limit?

    【讨论】:

    • 试过了,但不能在 has_one 关系中添加 :limit
    猜你喜欢
    • 2021-10-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多