繁体   English   中英

无法对 Yii2 中的 HasMany 关系进行排序

[英]Can't Sort HasMany Relationship in Yii2

我知道关于 Yii2 中的排序属性有很多问题。 我是使用这个框架的初学者,我已经用尽了所有可以在互联网上找到的参考资料。

所以对于第一部分。

我尝试在 Controller 上使用 orderBy 方法,但似乎也无法正常工作。

我的 controller 零件使用以下代码:

$saleModel = Sales::find()->with([
    'customer',
    'salesItems',
    'salesItems.item'
])->where(['id' => $id])->one();

现在我在这个 model 上有一个名为 Sales 的 Model 我与 SalesItems model 有很多关系。

public function getSalesItems()
{
    return $this->hasMany(SalesItems::className(), ['sale_id' => 'id'])
}

我已经尝试使用可以在此 Model 中找到的“item_id”对该 SalesItems model 进行排序,并且它正在工作。

public function getSalesItems()
{
    return $this->hasMany(SalesItems::className(), ['sale_id' => 'id'])
        ->orderBy(['item_id' => SORT_DESC]);
}

但我想要的是通过另一个连接的表/模型对我的 SalesItems 进行排序,该表/模型通过销售项目 model 中的 item_id 列连接。

在这种情况下,我有另一个名为 items 的表,它有一个 ID 列,这部分是他们加入['id' =>'item_id']地方。

总的来说,我想根据 items.name 对我的 SalesItems 进行排序。

我的 SQL 语句应该是这样的:

SELECT sales.id , sales.customer_id, sales_items.item_id, 
sales_items.sale_id, items.name FROM sales
INNER JOiN sales_items ON sales_items.sale_id = sales.id
INNER JOIN items ON sales_items.item_id = items.id WHERE sales.id =6374
ORDER BY items.name ASC;

我在 DB 上运行此 SQL 语句,并以我想要的方式成功检索结果。

这也是表模式:

在此处输入图像描述

希望有人能理解我一直在努力做的事情。

谢谢

你需要使用以下查询与joinWith来实现你想要的,你需要在列表中再选择一列i.id否则它只会显示一个项目。

$saleModel = Sales::find()->alias('s')
    ->select('s.id, s.customer_id, si.item_id, si.sale_id, i.name, i.id')
    ->joinWith(
        [
            'customer c',
            'salesItems si',
            'salesItems.item i'
        ], false, 'INNER JOIN'
    )
    ->where(['s.id' => 1])->orderBy('i.name ASC')->asArray()->all();

您可以尝试使用ActiveQuery的viaTable函数:

public function getSalesItems()
{
    return $this->hasMany(SalesItems::className(), ['sale_id' => 'id'])
         ->viaTable('items', ['id' => 'item_id'])
         ->orderBy(['items.name' => SORT_ASC]);
}

试试这些代码(他们在我的localhost上工作):

在控制器中:

$sales = Sales::find()->with([
            'customer',
            'salesItems',
            'salesItems.item'
        ])->where(['id' => 2])->asArray()->one();

要么

$db = Yii::$app->db;

        $query = $db->createCommand("SELECT sales.id , sales.customer_id, sales_items.item_id, 
                    sales_items.sale_id, items.name FROM sales
                    INNER JOiN sales_items ON sales_items.sale_id = sales.id
                    INNER JOIN items ON sales_items.item_id = items.id WHERE sales.id =2
                    ORDER BY items.name ASC;")->queryAll();

在SalesItems模型中:

<?php
//...
class SalesItems extends \yii\db\ActiveRecord
{
//...
public function getItem()
    {
        return $this->hasOne(Items::className(), ['id' => 'item_id']);
    }
//...
}

在销售模型中:

<?php
//...
class Sales extends \yii\db\ActiveRecord
//...
public function getSalesItems()
    {
        return $this->hasMany(SalesItems::className(), ['sale_id' => 'id'])->orderBy(['item_id' => SORT_DESC]);
    }

    public function getCustomer()
    {
        return $this->hasOne(Customers::className(), ['id' => 'customer_id']);
    }
// ...
}

使用活动记录:

     $query = Sales::find()->alias('sl')
        ->select('sl.id, sl.customer_id, si.item_id, si.sale_id, itm.name')
        ->joinWith('salesItem AS si', true)
        ->joinwith('salesItem.item AS itm')
        ->where(['si.id' => $id])
        ->orderBy(['itm.name' => SORT_ASC]);   

然后,您可以使用任何提供的方法来检索查询结果。 或者如果您想测试您的查询使用:

$sql = $query->createCommand()->sql; 

查看它是否与原始查询匹配。

我很少在大多数框架中使用关系功能,除了laravel,这限制了这个功能。

了解您提出的问题和ERD,我将为此特定问题建议一个简化的答案

我注意到si.sale_id连接到s.id ,因此在数值上等于保持关系

因此,这是我的首选解决方案

/**
 * 
 * @param integer $sales_id sales id
 * @return \frontend\models\SalesItems[] models
 */
public function getSalesItems($sales_id) {

    $s = \frontend\models\Sales::tableName();

    $si = \frontend\models\SalesItems::tableName();

    $i = \frontend\models\Items::tableName();

    return $this
                ->select('s.id, s.customer_id, si.item_id, si.sale_id, i.name')->from("$si si")
                ->leftJoin("$s s", "'$sales_id' = s.id")
                ->leftJoin("$i i", "si.item_id = i.id")
                ->where("si.sale_id = '$sales_id'")
                ->orderBy('i.name asc')
                ->all();
}

在SalesItems模型类中运行它

请仅在SalesItems模型类中引入以下两个属性(不是数据库表表),如下所示

class SalesItems extends \yii\db\ActiveRecord {

    // copy line below into SalesItems class
    public $name, $customer_id;

}

我相信它是这样高度优化的

希望能帮助到你

谢谢

我知道你问这个问题已经很久了。 我认为 1:n 关系的排序需要完成一些工作,或者它有一些我们无法发现的秘密。 我希望在 yii3 上它会得到解决。

但是对于您的问题,我复制了对您来说很常见的代码。 {{{{信息:我的规范值属于汽车轮胎参数}}}}

我有 1:n 关系( product_tbl 1:n productSpecificationValue_tbl() )每个产品都有很多规格,每个规格都有价值。 我想在 SPECIFICATION_VALUES 中排序我的 gridView

所以我为我想按它排序的每一个规范值编写单独的关系。 我需要其中的 3 个,所以我写了这 3 个关系:

<?php
 public function getProductTreadWidth()
    {
        return $this->hasOne(ProductSpecification::className(), ['product_id' => 'product_id'])->where(['specification_id' => 2]);

    }
    public function getProductAspectRatio()
    {
        return $this->hasOne(ProductSpecification::className(), ['product_id' => 'product_id'])->where(['specification_id' => 3]);
    }
    public function getProductDiameter()
    {
        return $this->hasOne(ProductSpecification::className(), ['product_id' => 'product_id'])->where(['specification_id' => 5]);
    }
?>

然后我获取 GET['sort'] 参数值,如果它是 productTreadWith 我让我的 DataProvider 加入到那个,如果它是 productAspectRatio 我让我的 DataProvider 加入到那个等等......就像下面的代码:

if(Yii::$app->request->get()['sort'] == 'productTreadWidth.value_en' || Yii::$app->request->get()['sort'] == '-productTreadWidth.value_en') {
                $joinTable = 'productTreadWidth';
            } elseif(Yii::$app->request->get()['sort'] == 'productAspectRatio.value_en' || Yii::$app->request->get()['sort'] == '-productAspectRatio.value_en') {
                $joinTable = 'productAspectRatio';
            } elseif(Yii::$app->request->get()['sort'] == 'productDiameter.value_en' || Yii::$app->request->get()['sort'] == '-productDiameter.value_en') {
                $joinTable = 'productDiameter';
            } else {
                $joinTable = 'productSpecificationsValuesIndexBySpecificationId';
            }
            $dataProvider = new ActiveDataProvider([
                'query' => Product::find()->joinWith(['brand', 'family', $joinTable ], true, 'LEFT JOIN')->where(['availability_id' => 1]),
           ]);

         $dataProvider->setSort([
                'attributes' => [
                    'productTreadWidth.value_en' => [
                        'asc' => ['value_en' => SORT_ASC],
                        'desc' => ['value_en' => SORT_DESC],
                        'label' => 'Tread Width',
                    ],

                    'productAspectRatio.value_en' => [
                        'asc' => ['value_en' => SORT_ASC],
                        'desc' => ['value_en' => SORT_DESC],
                        'label' => 'Aspect Ratio',
                    ],
                    'productDiameter.value_en' => [
                        'asc' => ['value_en' => SORT_ASC],
                        'desc' => ['value_en' => SORT_DESC],
                        'label' => 'Diameter',
                    ],
                   
                ],
            ]);

对于 gridView 我使用以下属性:

<?php
echo GridView::widget([
                'dataProvider' => $dataProvider,
                'columns' => [
                    ['class' => 'yii\grid\SerialColumn'],

                    [
                        'attribute' => 'brand.name_en',
                        'label' => 'Brand'

                    ],
                    [
                        'attribute' => 'family.name_en',
                        'label' => 'Model',
                    ],
                    [
                        'attribute' => 'productTreadWidth.value_en',
                        'label' => Yii::t('app' , 'Tire Width'),
                        'content' => function($model){
                            return $model->productTreadWidth['value_en'];
                        }
                    ],
                    [
                        'attribute' => 'productAspectRatio.value_en',
                        'label' => Yii::t('app' , 'Aspect Ratio'),
                        'content' => function($model){
                            return $model->productAspectRatio['value_en'];
                        }
                    ],
                ]
         ]);
?>

现在你可以对你喜欢的属性进行排序

我的问题要高一级:我想同时对 2 或 3 个属性进行排序 ASC 或 DESC

我希望3年后也有人回答我:D

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM