Domanda ActiveRecord dove e ordinare su via-table


Ho tre tabelle di database:

prodotto (id, nome)

product_has_adv (prodotto, vantaggio, ordinamento, importante)

vantaggio (id, testo)

In ProductModel ho definito questo:

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

Ottengo i vantaggi senza problemi.

Ma ora ho bisogno di aggiungere un dove product_has_advantage.important = 1 clausel e anche ordinare i vantaggi con il sort-columen nella tabella di prodotto_has_advantage.

Come e dove devo realizzarlo?


15
2017-12-29 14:07


origine


risposte:


utilizzando via e viaTable i metodi con le relazioni causeranno due query separate.

Puoi specificare callable nel terzo parametro come questo:

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]);
        });
}

Il filtro di important sarà applicato, ma l'ordinamento non lo farà poiché avviene nella prima query. Di conseguenza l'ordine degli ID in IN la dichiarazione sarà cambiata.

A seconda della logica del database, forse è meglio spostarsi important e sort colonne a advantage tavolo.

Quindi aggiungi le condizioni e ordina alla catena di metodi esistente:

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

32
2017-12-29 15:52



Solo per riferimento https://github.com/yiisoft/yii2/issues/10174 È quasi impossibile ORDER BY viaTable() colonne. Per Yii 2.0.7 restituisce un set di ID da viaTable() interrogazione, e finale / top query IN() la clausola ignora l'ordine.


3
2018-06-02 08:46



utilizzando viaTable i metodi con le relazioni causeranno due query separate, ma se non ne hai bisogno link() metodo è possibile utilizzare innerJoin nel seguente modo per ordinare per tabella 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;
}

Nota di $query->multiple = true ti permette di usare questo metodo come Yii2 ha molte relazioni.


2
2018-03-30 18:50



Per prima cosa devi creare un modello chiamato ProductHasAdv per la tabella di giunzione (product_has_adv) usando CRUD.

Quindi creare una relazione in product modella e ordinalo:

  public function getAdvRels()
    {
        return $this->hasMany(ProductHasAdv::className(), ['product' => 'id'])->
        orderBy(['sort' => SORT_ASC]);;
    }

Quindi crea una seconda relazione come questa:

public function getAdvantages()
{
    $adv_ids = [];
    foreach ($this->advRels as $adv_rel)
        $adv_ids[] = $adv_rel->advantage;
    return $this->hasMany(Advantage::className(), ['id' => 'advantage'])->viaTable('product_has_adv', ['product' => 'id'])->orderBy([new Expression('FIELD (id, ' . implode(',', $adv_ids) . ')')]);
}

Questo ordinerà il risultato finale usando order by FIELD tecnica.

Non dimenticare di aggiungere:

use yii\db\Expression;

linea a testa.


0
2018-01-08 23:38



Per chi viene qui dopo un po 'e non mi piacciono le soluzioni di cui sopra, l'ho fatto lavorando tornando al tavolo via dopo il filtro via tabella.

Esempio per il codice sopra:

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);
}

Abbi cura di cambiare XXX con il percorso di join corretto e YYY con la colonna di ordinamento corretta.


0
2017-07-07 10:21



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

-2
2017-07-11 07:27