[Yii2笔记]018 AR查询扩展字段(Selecting extra fields) [ 技术分享 ]
说明
学习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
(全文完)
共 0 条回复
阿江
最后登录:2024-03-03
在线时长:186小时21分
- 粉丝94
- 金钱16816
- 威望160
- 积分20276