• Yii2 ActiveRecord查询初探


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

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

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

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

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

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

    1.相关类结构

    (1)ActiveRecord相关类:

    yiidbActiveRecord extends yiidbBaseActiveRecord extends yiiaseModel

    (2)ActiveQuery相关类:

    yiidbActiveQuery extends yiidbQuery

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

    (3)yiidbCommand  yiidbConnection 与yiidbQueryBuilder联合起来,基于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()是yiidbQuery提供的方法,所以并未与ActiveRecord产生关联,只是用于构造Query对象的$join属性,以便构造sql语句使用;

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

    (3)with()是yiidbActiveQueryTrait提供的方法,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。

  • 相关阅读:
    微软API集
    如何在Visual Studio.net中让同一解决方案中包含多个不同类型的项目并共享同一命名空间
    总结:Asp.net页面之间传递参数的几种方法
    Javascript 鼠标滑过显示大图的效果
    HttpContext.Current.Session["key"]取值
    数字金额转大写
    整合多个图片到一个pdf
    .net reflector & disassembler
    yacc grammar for a simple shell
    Windows cmd编码
  • 原文地址:https://www.cnblogs.com/ling-diary/p/9193253.html
Copyright © 2020-2023  润新知