计数器

has_many 关系定义了一个属性,它是一个集合。它似乎能够回答有关集合大小的问题:
这个定单有多少个商品项目呢?实际上你会发现,聚合有个size()方法,它返回的就是这个
关联的对象数目。这个方法是深入到数据库在子表中执行select count(*)语句,计算外键
引用父表的相关记录数。
这个看起来是可行的。然而,如果你需要频繁的知道子项目的个数,这个额外的SQL 就
可能会是一个负担,你应该要避免。Active Record 使用了计数器缓存的技术有助于解决这
个问题。在子model 中的belongs_to 的声明,你可以要求Active Record 维护父表记录中关
联子表的记录数。这个计数是自动维护的--如果要增加一个子记录,在父表记录中的count
会自动增加,如果你删除的话,它就会被自动减数。
要激活这个特性,你只需简单的两步。首先,给在子表内belongs_to 声明
加:counter_cache 的选项。
class LineItem < ActiveRecord::Base
belongs_to :product, :counter_cache => true
end
其次,在父表定义中需要加入一个integer 列,它的名字是子表名+_count。
create table products (
id int not null auto_increment,
title varchar(100) not null,
/* . . .*/
line_items_count int default 0,
primary key (id)
);
在这个DDL 中有一点很重要。这个列必须要声明默认值为0,(或者你必须在父表记录
创建时设置为0)。如果不这样做,尽管有子表记录数,但最终你会得到null 值。
一旦你接受了这些步骤,你就会在父表记录中发现有计数器的列,它会自动跟踪子表的
记录数。
有一个与计数器缓存有关的问题。这个计数是由一个包含集合的对象来维护,并且如果
有什么往这个对象中添加会得到正确的更新。但是,你也可以在子表中直接设置连接来关联
子表和父表。这个情况下,计数器将不会得到更新。
下面是演示一个错误的做法,是把items 加入一个关联。我们手工来连接子表和父表。
注意size()属性是不正确的,直到我们强制父类去刷新集合。
product = Product.create(:title => "Programming Ruby",
:date_available => Time.now)
line_item = LineItem.new
line_item.product = product
line_item.save
puts "In memory size = #{product.line_items.size}"
puts "Refreshed size = #{product.line_items(:refresh).size}"
这是输出
In memory size = 0
Refreshed size = 1
正确的做法是把子类加到父类:
product = Product.create(:title => "Programming Ruby",
:date_available => Time.now)
product.line_items.create
puts "In memory size = #{product.line_items.size}"
puts "Refreshed size = #{product.line_items(:refresh).size}"
这次输出了正确数字。
In memory size = 1
Refreshed size = 1

你可能感兴趣的:(sql,cache,Ruby,ActiveRecord)