Conflits dans la clause where avec des noms de colonne ambigus


28

Un peu de contexte pour cela. Je souhaite étendre la fonction d'exportation de commande client (via la grille) pour avoir plus de colonnes. J'ai créé un module qui ajoute une nouvelle grille pour l'exportation et aussi un nouveau modèle de collection qui étend l'original. Cela utilise la fonction _beforeLoad () afin que je puisse rejoindre les tables dont j'ai besoin.

Le problème que j'ai est que lorsque les filtres de la grille sont ajoutés (increment_id, date de commande, etc.), la clause where que cela ajoute ne préfixe pas la table et je rencontre des problèmes avec les noms de colonnes ambigus. Par exemple, sur increment_id, j'ai le problème dans la clause where:

SELECT `main_table`.*, `sales`.`total_qty_ordered`, `sales`.`entity_id` AS `order_id`, `sagepay`.`vendor_tx_code` FROM `sales_flat_order_grid` AS `main_table`
 LEFT JOIN `sales_flat_order` AS `sales` ON main_table.increment_id = sales.increment_id
 LEFT JOIN `sagepaysuite_transaction` AS `sagepay` ON order_id = sagepay.order_id WHERE (increment_id LIKE '%100000261%') GROUP BY `main_table`.`entity_id`

Cette clause where est ajoutée avant de faire les jointures aux autres tables de la fonction _addColumnFilterToCollection ()

protected function _addColumnFilterToCollection($column)
    {
        if ($this->getCollection()) {
            $field = ( $column->getFilterIndex() ) ? $column->getFilterIndex() : $column->getIndex();
            if ($column->getFilterConditionCallback()) {
                call_user_func($column->getFilterConditionCallback(), $this->getCollection(), $column);
            } else {
                $cond = $column->getFilter()->getCondition();
                if ($field && isset($cond)) {
                    // Filter added at this point
                    $this->getCollection()->addFieldToFilter($field , $cond);
                }
            }
        }
        return $this;
    }

Comme un bref test, j'ai changé la ligne en

$this->getCollection()->addFieldToFilter('main_table.' . $field , $cond);

et cela a fonctionné, mais cela ne semble pas être une excellente façon de le faire.

Mon code dans _beforeLoad () est

protected function _beforeLoad()
{
    // Join the sales_flat_order table to get order_id and and total_qty_ordered
    $this->getSelect()->joinLeft(array('sales' => $this->getTable('sales/order')),
        'main_table.increment_id = sales.increment_id',
        array('total_qty_ordered' => 'sales.total_qty_ordered',
              'order_id' => 'sales.entity_id'));

    // Join the SagePay transaction table to get vendor_tx_code
    $this->getSelect()->joinLeft(array('sagepay' => $this->getTable('sagepaysuite2/sagepaysuite_transaction')),
        'order_id = sagepay.order_id',
        array('vendor_tx_code' => 'vendor_tx_code'));

    $this->getSelect()->group('main_table.entity_id');
    parent::_beforeLoad();
}

Je dois utiliser increment_id pour rejoindre la table de grille de commande client et la table de transaction SagePay car c'est le seul ID commun que je puisse voir.

Fondamentalement, je me demande quelle est la meilleure approche pour y remédier. Je pourrais probablement m'en tirer en faisant le changement que j'ai mentionné ci-dessus, mais cela ne me semble pas correct. Y a-t-il quelque chose que je puisse changer dans mes déclarations de jointure?

Merci.


1
Comment avez-vous rejoint les tables? Travailler sur le modèle Zend_Db_Select est une mauvaise idée, car magento enregistre les tables conjointes et ajoute normalement tous les préfixes. J'ai écrit un article de blog sur l'adhésion, peut-être que cela aide: blog.fabian-blechschmidt.de/articles/…
Fabian Blechschmidt

Merci pour la réponse, j'en aurai une lecture. J'ai essayé d'utiliser joinTable () mais il n'était pas disponible dans le modèle de collection.
Paul

Réponses:


52

Vous pouvez facilement résoudre toute condition ambiguë où en utilisant la méthode de collecte suivante:

  • addFilterToMap($filterName, $alias, $group = 'fields')
    • $filter- c'est le nom du filtre qui est utilisé dans la addFieldToFilter()méthode, pour votre cas c'estincrement_id
    • $alias- c'est le nom complet de la colonne qui est associée au filtre, pour vous c'est le cas main_table.increment_id.
    • $group - était destiné à être une carte pour tout type d'informations dans la collection, mais pour l'instant, il n'est utilisé que dans les filtres, vous pouvez donc omettre cet argument.

De plus, je ne pense pas que beforeLoad soit le bon endroit pour placer vos jointures, sauf si vous observez un événement. Dans votre cas, il est préférable de le déplacer dans la _initSelect()méthode en appelant avant parent::_initSelect(). Vous pouvez appeler la addFilterToMap()méthode à l'intérieur de votre _initSelect()méthode pour résoudre les conflits de jointure, comme ceci:

$this->addFilterToMap('increment_id', 'main_table.increment_id');

Par intérêt, pourquoi est-il préférable de faire les jointures dans _initSelect ()?
Paul

@Paul _initSelectn'est exécuté qu'une seule fois tout le temps, _beforeLoadpeut être appelé plus d'une fois, car vous pouvez load()collecter plusieurs fois si vous réinitialisez son état.
Ivan Chepurnyi

@Paul également, puisque _beforeLoad peut être appelé deux fois, vous recevrez une erreur fatale de Zend_Db_Select lors du deuxième appel.
Ivan Chepurnyi

2
J'ai fait quelque chose comme ça: $collection = Mage::getModel("education/ticket") ->getCollection() ->addFilterToMap('updated_at', 'main_table.updated_at') ->addFilterToMap('created_at', 'main_table.created_at');
FosAvance

@IvanChepurnyi, sont géniaux. Cela reflète que vous êtes excellent en tant qu'architecte Magento 1
Amit Bera
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.