首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

Rails 三 ActiveRecord的Relation源码剖析

2012-12-26 
Rails 3 ActiveRecord的Relation源码剖析Rails3的一大亮点是 AR的query 接口:1. 程序员最爱用就是它的及接

Rails 3 ActiveRecord的Relation源码剖析



Rails3的一大亮点是 AR的query 接口:

1. 程序员最爱用就是它的及接方式

Uers.where().where().order()....


2. 还有LasyLoad可以增加灵活性

=================

但这个Relation还是很让人迷惑的。尤其是一上来:

????? delegate :find, :first, :last, :all, :destroy, :destroy_all, :exists?, :delete, :delete_all, :update, :update_all, :to => :scoped
????? delegate :find_each, :find_in_batches, :to => :scoped
????? delegate :select, :group, :order, :reorder, :except, :limit, :offset, :joins, :where, :preload, :eager_load, :includes, :from, :lock, :readonly, :having, :create_with, :to => :scoped
????? delegate :count, :average, :minimum, :maximum, :sum, :calculate, :to => :scoped


这么生猛的操作都被delegate到:scoped上。不熟悉rails的手法,更是不知所云。

NamedScope scoped

知道调用 relation,new出一个relation实例就行了

@relation ||= Relation.new(self, arel_table)

这样,所以的操作都被delegate到relation实例上。

===================

relation查询接口都在relation目录下的query_methods.rb文件中

像order这种简单谓词

?def order(*args)
????? relation = clone
????? relation.order_values += args.flatten unless args.blank?
????? relation
??? end

就直接记到实例变量,后面产生sql用。

像where就复杂一些

def where(opts, *rest)
????? relation = clone
????? relation.where_values += build_where(opts, rest) unless opts.blank?
????? relation
??? end

build_where又调用了predicate_builder来builderwhere_value。在这里也是用了arel

================================

这些query动作完后,用all, first, last来向db fetch东西,最重要的东西来了!

调用relation to_a方法

? def to_a
????? return @records if loaded?

????? @records = eager_loading? ? find_with_associations : @klass.find_by_sql(arel.to_sql)
...
????? @records
??? end

让are生成to_sql,还用是AR的base中的connection用查询数据回来

那么arel是如何生成的呢

def build_arel
????? arel = table

????? arel = build_joins(arel, @joins_values) unless @joins_values.empty?

????? arel = collapse_wheres(arel, (@where_values - ['']).uniq)

????? arel = arel.having(*@having_values.uniq.reject{|h| h.blank?}) unless @having_values.empty?

????? arel = arel.take(connection.sanitize_limit(@limit_value)) if @limit_value
????? arel = arel.skip(@offset_value) if @offset_value

????? arel = arel.group(*@group_values.uniq.reject{|g| g.blank?}) unless @group_values.empty?

????? arel = arel.order(*@order_values.uniq.reject{|o| o.blank?}) unless @order_values.empty?

????? arel = build_select(arel, @select_values.uniq)

????? arel = arel.from(@from_value) if @from_value
????? arel = arel.lock(@lock_value) if @lock_value

????? arel
??? end

arel本身可以不断及连。

========================

到时,真相大白。

relation是一个逻辑体,可以不断及联。are是一个sql factory。 AR:base是实体,有数据库连接。

那么要hook住AR的query,只要hook在relation的to_a方法上。

========================

设计上可以参考是:

1. 及联,类似decorator模式
?
2. base, relation, arel这种实体,逻辑体,工厂互相协同,松耦合,可扩展


热点排行