浏览 3636 次
精华帖 (0) :: 良好帖 (4) :: 新手帖 (0) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2007-06-26
ActiveRecord默认是lazy loading的,而加上:include选项后可以指定eager loading一些字段 :include - specify second-order associations that should be eager loaded when the collection is loaded. 看例子: Post.find(:all, :include => :comments) # => SELECT ... FROM posts LEFT OUTER JOIN comments ON ... 我再把active_recordassociations.rb的源代码翻出来给大家看看: 1,base.rb def with_scope(method_scoping = {}, action = :merge, &block) method_scoping = method_scoping.method_scoping if method_scoping.respond_to?(:method_scoping) # Dup first and second level of hash (method and params). method_scoping = method_scoping.inject({}) do |hash, (method, params)| hash[method] = (params == true) ? params : params.dup hash end method_scoping.assert_valid_keys([ :find, :create ]) if f = method_scoping[:find] f.assert_valid_keys([ :conditions, :joins, :select, :include, :from, :offset, :limit, :order, :readonly, :lock ]) f[:readonly] = true if !f[:joins].blank? && !f.has_key?(:readonly) end # Merge scopings if action == :merge && current_scoped_methods method_scoping = current_scoped_methods.inject(method_scoping) do |hash, (method, params)| case hash[method] when Hash if method == :find (hash[method].keys + params.keys).uniq.each do |key| merge = hash[method][key] && params[key] # merge if both scopes have the same key if key == :conditions && merge hash[method][key] = [params[key], hash[method][key]].collect{ |sql| "( %s )" % sanitize_sql(sql) }.join(" AND ") elsif key == :include && merge hash[method][key] = merge_includes(hash[method][key], params[key]).uniq else hash[method][key] = hash[method][key] || params[key] end end else hash[method] = params.merge(hash[method]) end else hash[method] = params end hash end end self.scoped_methods << method_scoping begin yield ensure self.scoped_methods.pop end end def find_every(options) records = scoped?(:find, :include) || options[:include] ? find_with_associations(options) : find_by_sql(construct_finder_sql(options)) records.each { |record| record.readonly! } if options[:readonly] records end 2,associations.rb module ActiveRecord module Associations module ClassMethods private def find_with_associations(options = {}) catch :invalid_query do join_dependency = JoinDependency.new(self, merge_includes(scope(:find, :include), options[:include]), options[:joins]) rows = select_all_rows(options, join_dependency) return join_dependency.instantiate(rows) end [] end def select_all_rows(options, join_dependency) connection.select_all( construct_finder_sql_with_included_associations(options, join_dependency), "#{name} Load Including Associations" ) end def construct_finder_sql_with_included_associations(options, join_dependency) scope = scope(:find) sql = "SELECT #{column_aliases(join_dependency)} FROM #{(scope && scope[:from]) || options[:from] || table_name} " sql << join_dependency.join_associations.collect{|join| join.association_join }.join add_joins!(sql, options, scope) add_conditions!(sql, options[:conditions], scope) add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit]) sql << "GROUP BY #{options[:group]} " if options[:group] add_order!(sql, options[:order], scope) add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections) add_lock!(sql, options, scope) return sanitize_sql(sql) end class JoinDependency class JoinAssociation < JoinBase def association_join join = case reflection.macro when :has_and_belongs_to_many " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [ table_alias_for(options[:join_table], aliased_join_table_name), aliased_join_table_name, options[:foreign_key] || reflection.active_record.to_s.classify.foreign_key, parent.aliased_table_name, reflection.active_record.primary_key] + " LEFT OUTER JOIN %s ON %s.%s = %s.%s " % [ table_name_and_alias, aliased_table_name, klass.primary_key, aliased_join_table_name, options[:association_foreign_key] || klass.table_name.classify.foreign_key ] when :has_many, :has_one ... when :belongs_to ... else ... join end end end 调用流程是这样的: ActiveRecord.find* -> with_scope -> find_every -> find_with_associations -> select_all_rows -> construct_finder_sql_with_included_associations -> association_join 如果提供:include选项,则调用find_with_associations,即eager loading,否则调用find_by_sql,为lazy loading 最后我们看到JoinAssociation的association_join方法使用LEFT OUTER JOIN来做关联查询,做eager loading 一切都弄清楚了吧? BTW:对于open source项目,遇到问题时看看source code是很好的solution 声明:ITeye文章版权属于作者,受法律保护。没有作者书面许可不得转载。
推荐链接
|
|
返回顶楼 | |