yii2tech/ar-eagerjoin

该包已被弃用且不再维护。未建议替代包。

为 Yii2 提供通过连接而不进行额外查询的 ActiveRecord 关联预加载支持

资助包维护!
klimov-paul
Patreon

安装: 16,133

依赖: 0

建议者: 0

安全: 0

星标: 22

关注者: 4

分支: 0

开放问题: 0

类型:yii2-extension

1.0.2 2019-01-24 15:53 UTC

This package is auto-updated.

Last update: 2022-01-10 10:34:07 UTC


README

12951949

为 Yii 2 的 ActiveRecord 预连接扩展


此扩展提供了通过 '连接' 而不进行额外查询的 ActiveRecord 关联预加载支持。

有关许可信息,请参阅 LICENSE 文件。

Latest Stable Version Total Downloads Build Status

安装

安装此扩展的首选方式是通过 composer

运行以下命令:

php composer.phar require --prefer-dist yii2tech/ar-eagerjoin

或添加以下内容到你的 composer.json 中的 require 部分:

"yii2tech/ar-eagerjoin": "*"

用法

此扩展提供了通过 '连接' 而不进行额外查询的 ActiveRecord 关联预加载支持。假设我们有一个以下数据库结构

CREATE TABLE `Group`
(
   `id` integer NOT NULL AUTO_INCREMENT,
   `name` varchar(64) NOT NULL,
   `code` varchar(10) NOT NULL,
    PRIMARY KEY (`id`)
) ENGINE InnoDB;

CREATE TABLE `Item`
(
   `id` integer NOT NULL AUTO_INCREMENT,
   `groupId` integer NOT NULL,
   `name` varchar(64) NOT NULL,
   `price` float,
    PRIMARY KEY (`id`)
    FOREIGN KEY (`groupId`) REFERENCES `Group` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
) ENGINE InnoDB;

如果您需要显示项目的列表,以及它们所属的组,按组名或代码排序,您将不得不使用 JOIN SQL 语句,因此需要使用 \yii\db\ActiveQuery::joinWith() 方法

$items = Item::find()
    ->joinWith('group')
    ->orderBy(['{{group}}.[[name]]' => SORT_ASC])
    ->all();

然而,上面的代码将执行 2 个 SQL 查询:一个用于获取项目(包括 JOINORDER BY 语句),另一个用于获取组。虽然第二个查询将非常简单且快速,但它仍然是多余的且效率低下,因为所有组列都可能与项目列一起被选择。

此扩展提供了 [[yii2tech\ar\eagerjoin\EagerJoinTrait]] 特性,一旦在 ActiveRecord 类中使用,就可以在不执行额外 SQL 查询的情况下选择相关记录。

设置示例

use yii\db\ActiveRecord;
use yii2tech\ar\eagerjoin\EagerJoinTrait;

class Item extends ActiveRecord
{
    use EagerJoinTrait;

    public function getGroup()
    {
        return $this->hasOne(Group::className(), ['id' => 'groupId']);
    }
}

为了通过 '连接' 查询填充相关记录,您需要手动将它们的列追加到 SELECT 查询部分,并使用以下格式的名称对它们进行别名

{relationName}{boundary}{columnName}

其中

  • 'relationName' - 要填充的关联名称
  • 'columnName' - 要填充的相关记录的列(属性)名称
  • 'boundary' - 由 [[yii2tech\ar\eagerjoin\EagerJoinTrait::eagerJoinBoundary()]] 配置的分隔符

例如

$items = Item::find()
    ->select(['Item.*', 'group__name' => 'Group.name', 'group__code' => 'Group.code'])
    ->joinWith('group', false) // disable regular eager loading!!!
    ->all();

foreach ($items as $item) {
    var_dump($item->isRelationPopulated('group')); // outputs `true`!!!
    echo $item->group->name; // no extra query performed!
    echo $item->group->code; // no extra query performed!
    echo get_class($item->group); // outputs 'Group'!
}

在这里,查询结果集的 'group__name' 列传递给 $item->group->name,'group__code' - 到 $item->group->code 等等。

请注意!不要忘记禁用预加载,通过将 false 作为 joinWith() 方法的第二个参数传递,否则您将不会获得任何好处。

注意:请仔细选择 boundary:它不应作为非预期传递给相关记录的列(或别名)的一部分存在。因此,双下划线 ('__') 被用作默认值。

提示:如果您使用 'camelCase' 语法表示表列,则可以使用单下划线 ('_') 作为边界,以便使选择语句更加清晰。

您可以使用 [[\yii2tech\ar\eagerjoin\EagerJoinQueryTrait]] 特性来加快查询的编写速度。此特性应在 [[\yii\db\ActiveQuery]] 实例中使用

use yii\db\ActiveQuery;
use yii2tech\ar\eagerjoin\EagerJoinQueryTrait;
use yii\db\ActiveRecord;
use yii2tech\ar\eagerjoin\EagerJoinTrait;

class ItemQuery extends ActiveQuery
{
    use EagerJoinQueryTrait;

    // ...
}

class Item extends ActiveRecord
{
    use EagerJoinTrait;

    /**
     * @inheritdoc
     * @return ItemQuery the active query used by this AR class.
     */
    public static function find()
    {
        return new ItemQuery(get_called_class());
    }

    // ...
}

在构建查询时,您将能够使用 eagerJoinWith() 方法。

$items = Item::find()->eagerJoinWith('group')->all();

适当的 'select' 和 'join' 语句的组合将自动执行。

限制和缺点

虽然减少了执行的查询数量,但此扩展有几个限制和缺点。

  1. 仅支持 'has-one' 关系。扩展无法处理 'has-many' 关系。您应该使用常规的 joinWith() 和懒加载来处理 'has-many' 关系。

  2. 如果所有选择的相关模型字段都将为 null,则整个相关记录将被设置为 null。您应该始终选择至少一个 '非 null' 列,以避免不适当的结果。

  3. 尽管移除了额外的查询,但此扩展实际上可能不会提高整体性能。常规 Yii 懒加载查询非常简单且快速,而此扩展会消耗额外的内存并执行额外的计算。因此,性能几乎保持不变。在大多数情况下,使用此扩展是一种权衡:它减少了数据库端的负载,同时增加了 PHP 端的负载。