2012-11-24 68 views
3

我使用的是counter_cache让MySQL的做一些簿记对我说:counter_cache不更新的模型保存后

class Container 
    has_many :items 
end 

class Item 
    belongs_to :container, :counter_cache => true 
end 

现在,如果我这样做:在

container = Container.find(57) 
item = Item.new 
item.container = container 
item.save 

SQL日志会有一个INSERT其次是这样的:

UPDATE `containers` SET `items_count` = COALESCE(`items_count`, 0) + 1 
    WHERE `containers`.`id` = 57 

这是我的前把它做了。但是,container[:items_count]将陈旧!

...除非我container.reload拿起更新的值。在我的脑海里,有些人认为使用:counter_cache支持定制内容的一部分目的,特别是因为在尝试访问items_count属性之前,我实际上可能不需要reload。 (由于域逻辑的性质,我的模型非常密码化,所以我有时必须在一次控制器调用中保存并创建多件事情。)

我知道我可以自己修改回调,但在我看来,这似乎是对简单功能的一个相当基本的期望。同样,如果我必须编写额外的代码才能使其完全工作,那么实现自定义计数器可能会更容易。

我在做什么/假设错误?

回答

1

虽然实际上并没有让容器知道该项目,但实际上,您在container.reload时执行的操作是!它。您是否尝试过:

container = Container.find(57) 
item = container.items.create() 

这将使容器的上下文中的项目和为您建立这些关联。

+0

这有效。我发现它不一致,它是一种方式而不是另一种。 – sehnsucht

+0

对我来说这不起作用!只有在重载计数器更新后。我尝试了各种样式'create','create!','build.save!'。 – pablo

3

您不应该期望在您的容器实例中自动更新项目计数器的值。请记住,大多数Rails应用程序在多进程(通常是多服务器)配置下运行。如果一个进程在不同进程中添加与Container实例关联的Item,则计数器的值将变为陈旧。

+1

保持数据处于一致状态的负担在模型上。这就是为什么我们拥有不同的隔离级别的交易,并且如果拥塞足够高以保证它的话,那么它就是乐观并发的原因。有人可能会在其他地方更改数据不仅适用于counter_cache,而且还是一个普遍问题 - 如果第二个表已更新,则连续两个SELECT可能会产生不一致的数据。 在这方面,我不明白为什么由其他人向我的容器添加项目导致的竞争条件与我在访问它之前更改'container.items'的任何不同。 – sehnsucht