ActiveRecord在via-table的位置和顺序

rak*_*ete 18 activerecord yii2

我有三个数据库表:

产品(id,名称)

product_has_adv(产品,优势,排序,重要)

优势(身份证,文字)

在ProductModel中我定义了这个:

public function getAdvantages()
    {
        return $this->hasMany(AdvantageModel::className(), ['id' => 'advantage'])
            ->viaTable('product_has_advantage', ['product' => 'id']);
    }
Run Code Online (Sandbox Code Playgroud)

我毫无问题地获得了优势.

但是现在我需要添加一个product_has_advantage.important = 1 clausel,并通过product_has_advantage-table中的sort-columen对优势进行排序.

我如何以及在哪里实现它?

aro*_*hev 35

使用viaviaTable关系方法将导致两个单独的查询.

您可以在第三个参数中指定callable,如下所示:

public function getAdvantages()
{
    return $this->hasMany(AdvantageModel::className(), ['id' => 'advantage'])
        ->viaTable('product_has_advantage', ['product' => 'id'], function ($query) {
            /* @var $query \yii\db\ActiveQuery */

            $query->andWhere(['important' => 1])
                ->orderBy(['sort' => SORT_DESC]);
        });
}
Run Code Online (Sandbox Code Playgroud)

important将应用过滤器,但排序不会,因为它发生在第一个查询中.因此,IN语句中的ID顺序将被更改.

根据您的数据库逻辑,最好将列importantsort列移动到advantage表中.

然后只需添加条件并对现有方法链进行排序:

public function getAdvantages()
{
    return $this->hasMany(AdvantageModel::className(), ['id' => 'advantage'])
        ->viaTable('product_has_advantage', ['product' => 'id'])
        ->andWhere(['important' => 1])
        ->orderBy(['sort' => SORT_DESC]);
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么这是公认的答案?我有同样的问题(需要对“viatable”中定义的表进行排序)并将列移动到另一个表是不可接受的。 (2认同)

小智 5

仅供参考https://github.com/yiisoft/yii2/issues/10174列 几乎是不可能的ORDER BY viaTable()。对于 Yii 2.0.7,它从查询中返回 ID 集viaTable(),并且最终/顶部查询IN()子句忽略顺序。


小智 5

使用viaTable具有关系的方法将导致两个单独的查询,但是如果不需要link()方法,则可以按以下方式使用innerJoin按product_has_advantage表进行排序:

public function getAdvantages()
{
    $query = AdvantageModel::find();
    $query->multiple = true;
    $query->innerJoin('product_has_advantage','product_has_advantage.advantage = advantage.id');
    $query->andWhere(['product_has_advantage.product' => $this->id, 'product_has_advantage.important' => 1]);
    $query->orderBy(['product_has_advantage.sort' => SORT_DESC]);
    return $query;
}
Run Code Online (Sandbox Code Playgroud)

注意,$query->multiple = true因为Yii2具有hasMany关系,因此允许您使用此方法。


小智 5

对于一段时间后来到这里并且不喜欢上述解决方案的人,我通过在过滤器通过表之后连接回到通过表来使其工作。

上述代码示例:

public function getAdvantages()
{
    return $this->hasMany(AdvantageModel::className(), ['id' => 'advantage'])
        ->viaTable('product_has_advantage', ['product' => 'id'])
        ->innerJoin('product_has_advantage','XXX')
        ->orderBy('product_has_advantage.YYY'=> SORT_ASC);
}
Run Code Online (Sandbox Code Playgroud)

请注意使用正确的连接路径更改 XXX,并使用正确的排序列更改 YYY。