Yii2 ActiveRecord查询初探

梳理一下Yii2中ActiveRecord一次查询的大致流程,理解如下几个问题:

(1)ActiveRecord与ActiveQuery何时产生联系;

(2)ActiveQuery怎样与数据库连接Connection产生关系;

(3)ActiveRecord查询为何能返回ActiveRecord对象;

(4)join(),joinWith()与with()有什么关系与区别;

(5)ActiveRecord关联查询怎样做到面向对象访问关联属性,它与普通的Query查询有何区别。

1.相关类结构

(1)ActiveRecord相关类:

yii\db\ActiveRecord extends yii\db\BaseActiveRecord extends yii\base\Model

(2)ActiveQuery相关类:

yii\db\ActiveQuery extends yii\db\Query

另有一些Trait提供关联查询功能,这里暂不详细列出,当作query类方法来描述。

(3)yii\db\Command  yii\db\Connection 与yii\db\QueryBuilder联合起来,基于\Pdo实现基本的数据库连接与查询。

2.ActiveRecord::find()->one();执行流程:

(1)ActiveRecord::find()实例化一个ActiveQuery对象并返回;

(2)ActiveQuery::one()会调用Query::one()获取查询结果,并对结果进行populate(),以便把数据库查询的数组结构的结果集渲染为具体的ActiveRecord对象结果集;

(3)Query::one()执行流程:

    1)通过QueryBuilder::build()构造查询所需的sql语句与关联参数;

    2)调用Connection::createCommand()实例化一个Command对象;

    3)通过Command::queryOne()获取查询结果集。

(4)Command::queryOne()实际会调用Command::queryInternal():

    1)首先判断是否开启了数据缓存,若开启则先在缓存中查找结果集,没有则继续执行以下步骤,这里对Yii的数据缓存不展开讨论;

    2)执行Command::prepare()经由Connection获得当前数据库连接的\Pdo对象,通过Pdo对象的prepare()方法获得一个\PdoStatement对象;

    3)通过上一步获得的PdoStatement对象获取并返回查询结果集。

(5)ActiveRecord的populate过程:

    1)根据数据库查询结果集的数据构造对应的主ActiveRecord对象;

    2)通过findWith()处理eagerLoading类型的关联属性,也是ActiveRecord查询结果可以以面向对象的方式访问关联查询结果的关键所在,这一问题并未在上图中展开,下面是具体分析。

3.join(), joinWith()与with()

通过阅读源码大概掌握了这三个方法干了些什么:

(1)join()是yii\db\Query提供的方法,所以并未与ActiveRecord产生关联,只是用于构造Query对象的$join属性,以便构造sql语句使用;

(2)joinWith()是yii\db\ActiveQuery的方法,抛开它支持的多种关联定义方式,仅仅是将关联信息放入ActiveQuery的$joinWith属性中;

(3)with()是yii\db\ActiveQueryTrait提供的方法,ActiveQuery使用了这个Trait。同样抛开它多样化的参数,它仅仅是将关联属性信息存入ActiveQuery的$with属性中。

到这里没有什么进展,还要继续看查询过程中哪里用到了$join,$joinWith与$with这三个属性:

(1)在ActiveQuery::prepare()方法中调用了buildJoinWith()方法,这里处理$joinWith属性内容,将其全部加到$join属性中,并将eagerLoading为true的内容同时加入到$with属性中,至此,$joinWith属性的任务结束;

(2)在ActiveRecord::populate()方法中调用了findWith()方法,这里处理$with属性的内容,对每条查询结果逐个查询$with中定义的关联属性结果集并实例化为对应的关联ActiveRecord对象,通过主ActiveRecord对象的populateRelation()方法实现属性关联。至此,ActiveRecord的查询结果已经可以像访问属性一样访问关联查询结果了。

4.Query与ActiveQuery在联表查询上的区别

(1)Query处理联表查询是中规中矩的sql查询方式,所有关联结果与主表结果在一次查询中获得并在同一结果集中返回;

(2)ActiveQuery的联表查询比较特殊,它为了实现面向对象的关联属性访问方式,需要经过多次查询来构造关联ActiveRecord对象:

    1)join()与joinWith()方法均是$join属性的定义入口,在ActiveQuery中虽然最终构造出的sql语句包含$join属性定义的所有关联,但除非在select()方法中包含关联属性,否则默认生成的sql只查询主表的字段,查询结果中将不包含任何关联表数据,而且在populateRecord过程中也只能处理主表字段;

    2)关联属性如果来自with()或指定eagerLoading为true的joinWith()方法,即被包含在$with属性中,则在渲染完主表的查询结果后,会逐个查询关联结果并渲染关联属性;

    3)若通过joinWith()定义关联并指定eagerLoading为false,则直到显示读取该关联属性时才会执行关联结果查询与渲染,这就是LazyLoading。

猜你喜欢

转载自www.cnblogs.com/ling-diary/p/9193253.html