阿江 2017-10-01 16:17:19 5287次浏览 0条回复 0 0 0

说明

学习Yii Framework 2易2框架的过程是漫长的也是充满乐趣的以下是我学习Yii2框架时对官网英文资料(请参见原文网址)的翻译和代码实现提供了较完整的代码供你参考不妥之处请多多指正

原文网址:

http://www.yiiframework.com/doc-2.0/guide-db-active-record.html#selecting-extra-fields
14、Selecting extra fields(查询扩展字段)

本文主题:AR查询扩展字段(Selecting extra fields)

14、查询扩展字段(Selecting extra fields)

当Active Record实例是由查询数据填充时,它的属性值将由接收到的数据集中对应列来填充。 你可以从查询中获取额外的列或值,并将它存储到Active Record中,例如,假定我们现在有一个room表,它包含了酒店有效的房间信息,每个房间使用字段length、width、height存储了它的空间信息,想象一下,我们需要获取子订单中所有有效房间的体积,因为我们需要根据体积的值来排序,所以你不能使用PHP在计算此列值,但你需要将此列值显示在列表中,要实现这个目标,你需要在Room的AR类中声明一个额外的字段,用于存储volume值:

class Room extends \yii\db\ActiveRecord
{
    public $volume;
    // ...
}

接下来,你需要构建一个查询,用它来计算房间的体积(volume)并执行排序:

$rooms = Room::find()
    ->select([
        '{{room}}.*', // select all columns
		//mongodb不支持as定义
        '([[length]] * [[width]] * [[height]]) AS volume', // calculate a volume
    ])
    ->orderBy('volume DESC') // apply sort
    ->all();

foreach ($rooms as $room) {
    echo $room->volume; // contains value calculated by SQL
}
文件位置:
D:\phpwork\basic\controllers\ArticleController.php
源代码:
//选择额外的字段实例(mariadb)
        $articles=\app\models\CountryMysql::find()
            ->select([
                'name',
                '([[population]]+[[id]]) AS aa',
            ])
            ->limit(2)->asArray()->all();
        var_dump($articles);
测试结果:
/*
array (size=2)
  0 => 
    array (size=2)
      'name' => string 'Australia' (length=9)
      'aa' => string '18886001' (length=8)
  1 => 
    array (size=2)
      'name' => string 'Brazil' (length=6)
      'aa' => string '170115002' (length=9)
*/

查询扩展字段的特性对于聚合查询特别有用,假设你需要显示客户列表,并查询他们下单的数量,首先,你需要声明带有orders关联的Customer类,并用扩展字段去存储计数值:

class Customer extends \yii\db\ActiveRecord
{
    public $ordersCount;

    // ...

    public function getOrders()
    {
        return $this->hasMany(Order::className(), ['customer_id' => 'id']);
    }
}

接下来,你可以构建一个查询,将联查订单并计算他们总数。

$customers = Customer::find()
    ->select([
        '{{customer}}.*', // select all customer fields
        'COUNT({{order}}.id) AS ordersCount' // calculate orders count
    ])
    ->joinWith('orders') // ensure table junction
    ->groupBy('{{customer}}.id') // group the result to ensure aggregation function works
    ->all();

使用此方法的不好之处在于,如果这些信息没有在SQL查询中加载,它将被单独计算,所以,如果你使用常规查询而不是扩展查询语句去查询到了特定的记录,它将不能为扩展字段返回实际值,当存储新记录时也会发生相同的事情。

$room = new Room();
$room->length = 100;
$room->width = 50;
$room->height = 2;
$room->volume; // this value will be `null`, since it was not declared yet

使用get()和set()魔术方法我们可以模拟一个属性的此方法:

class Room extends \yii\db\ActiveRecord
{
    private $_volume;
    public function setVolume($volume)
    {
        $this->_volume = (float) $volume;
    }
    public function getVolume()
    {
        if (empty($this->length) || empty($this->width) || empty($this->height)) {
            return null;
        }
        if ($this->_volume === null) {
            $this->setVolume(
                $this->length * $this->width * $this->height
            );
        }
        return $this->_volume;
    }
    // ...
}

当查询语句没有提供体积字段时,此模型可以使用此模型的属性值自动计算出来。 你可以使用定义的关联计算聚合字段:

class Customer extends \yii\db\ActiveRecord
{
    private $_ordersCount;
    public function setOrdersCount($count)
    {
        $this->_ordersCount = (int) $count;
    }
    public function getOrdersCount()
    {
        if ($this->isNewRecord) {
            return null; // this avoid calling a query searching for null primary keys
        }
        if ($this->_ordersCount === null) {
            $this->setOrdersCount($this->getOrders()->count()); // calculate aggregation on demand from relation
        }
        return $this->_ordersCount;
    }
    // ...
    public function getOrders()
    {
        return $this->hasMany(Order::className(), ['customer_id' => 'id']);
    }
}

使用上述代码,orderCount代表了查询语句Customer::orderCount,将被填充到查询结果中,否则它将在使用Customer::order关联时按需计算。

//查询数量总数的实例:
   public function getTagsCount() {
        return $this->hasMany(Tags::className(), ['_id' => 'tagId'])
            ->select(['_id','tagId'])
            ->via('articleTags')
            ->count();
    }
	//与上例方法getTagsCount()同效:
    public function getTagsCount2() {		
        return $this->getAllTags()->count();
    }

此方法可以被用于为关联数据创建快捷方式,尤其是聚合字段,例如:

class Customer extends \yii\db\ActiveRecord
{
    /**
     * Defines read-only virtual property for aggregation data.
     */
    public function getOrdersCount()
    {
        if ($this->isNewRecord) {
            return null; // this avoid calling a query searching for null primary keys
        }
        return empty($this->ordersAggregation) ? 0 : $this->ordersAggregation[0]['counted'];
    }
    /**
     * Declares normal 'orders' relation.
     */
    public function getOrders()
    {
        return $this->hasMany(Order::className(), ['customer_id' => 'id']);
    }
    /**
     * Declares new relation based on 'orders', which provides aggregation.
     */
    public function getOrdersAggregation()
    {
        return $this->getOrders()
            ->select(['customer_id', 'counted' => 'count(*)'])
            ->groupBy('customer_id')
            ->asArray(true);
    }
    // ...
}
foreach (Customer::find()->with('ordersAggregation')->all() as $customer) {
    echo $customer->ordersCount; // outputs aggregation data from relation without extra query due to eager loading
}
$customer = Customer::findOne($pk);
$customer->ordersCount; // output aggregation data from lazy loaded relation

(全文完)

    没有找到数据。
您需要登录后才可以回复。登录 | 立即注册