这是前段时间有人讨论过的问题:
代码:
order = Order.find(1) order.update_attribute(:status, 'finished') 假定orders表有10个字段,你只想更新其中一个,但active record会生成一个更新全部字段的SQL语句,假定其中一个字段值长度是20K,这个负担可能会有些重。 我尝试解决这个问题,写了个简单的插件:
代码:
module ActiveRecord class Base def update_attribute(name, value) update_attributes(name => value) end def update_attributes(new_attributes) return if new_attributes.nil? attributes = new_attributes.dup attributes.stringify_keys! self.attributes = attributes update(attributes) end private def update(attrs = nil) connection.update( "UPDATE #{self.class.table_name} " + "SET #{quoted_comma_pair_list(connection, attributes_with_quotes(false, attrs))} " + "WHERE #{self.class.primary_key} = #{quote(id)}", "#{self.class.name} Update" ) return true end def attributes_with_quotes(include_primary_key = true, attrs = nil) (attrs || attributes).inject({}) do |quoted, (name, value)| if column = column_for_attribute(name) quoted[name] = quote(value, column) unless !include_primary_key && column.primary end quoted end end end end
attributes_with_quotes函数的参数搞这么复杂,原因是我想即便是用这段代码替换库里面的部分,也不影响原有代码的正常功能。 可以简单测试一下上面的例子,它生成的SQL语句会简洁很多,大概是这样子: UPDATE orders SET "status" = 'finished' WHERE id = 1已发现的BUG和修复:1、没有调用validation (by cookoo)。由于原有代码调用save,而save被覆盖成有验证的代码,所以具有验证功能。解决办法是增加一段代码:
module ActiveRecord module ValidationsFix def self.append_features(base) # :nodoc: super base.class_eval do alias_method :update_attributes_without_validation, :update_attributes alias_method :update_attributes, :update_attributes_with_validation end end def update_attributes_with_validation(new_attributes) return if new_attributes.nil? attributes = new_attributes.dup attributes.stringify_keys! self.attributes = attributes if valid? update_attributes_without_validation(attributes) else return false end end endendActiveRecord::Base.class_eval do include ActiveRecord::ValidationsFixend
简单测试通过。 |