Conflitti nella clausola where con nomi di colonne ambigui


28

Un po 'di contesto per questo. Voglio estendere la funzione di esportazione dell'ordine di vendita (tramite la griglia) per avere più colonne. Ho creato un modulo che aggiunge una nuova griglia per l'esportazione e anche un nuovo modello di raccolta che estende l'originale. Questo utilizza la funzione _beforeLoad () in modo da poter unire le tabelle di cui ho bisogno.

Il problema che sto riscontrando è che quando vengono aggiunti i filtri dalla griglia (increment_id, data ordine ecc.), La clausola where aggiunta non precede la tabella e sto riscontrando problemi con nomi di colonna ambigui. Ad esempio, su increment_id sto riscontrando il problema nella clausola 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`

Questa clausola dove viene aggiunta prima di eseguire i join alle altre tabelle nella funzione _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;
    }

Come breve test, ho cambiato la linea in

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

e questo ha funzionato ma non sembra un ottimo modo per farlo.

Il mio codice in _beforeLoad () è

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

Devo utilizzare increment_id per unirmi alla tabella della griglia degli ordini di vendita e alla tabella delle transazioni di SagePay poiché questo è l'unico ID comune che posso vedere.

Fondamentalmente mi chiedo quale sia l'approccio migliore per affrontarlo. Probabilmente potrei cavarmela facendo il cambiamento che ho menzionato sopra, ma non mi sembra giusto. C'è qualcosa che posso cambiare nelle mie dichiarazioni di partecipazione?

Grazie.


1
Come ti sei unito ai tavoli? Lavorare sul modello Zend_Db_Select è una cattiva idea, perché magento registra le tabelle comuni e aggiunge normalmente tutti i prefissi. Ho scritto un articolo di blog sull'adesione
Fabian Blechschmidt,

Grazie per la risposta, ne avrò letto. Ho provato a utilizzare joinTable () ma non era disponibile nel modello di raccolta.
Paul

Risposte:


52

È possibile risolvere facilmente qualsiasi condizione ambigua dove utilizzare il seguente metodo di raccolta:

  • addFilterToMap($filterName, $alias, $group = 'fields')
    • $filter- è il nome del filtro utilizzato nel addFieldToFilter()metodo, nel tuo caso lo èincrement_id
    • $alias- è il nome completo della colonna associata al filtro, nel tuo caso lo è main_table.increment_id.
    • $group - doveva essere una mappa per qualsiasi tipo di informazione nella raccolta, ma per ora è usata solo nei filtri, quindi puoi omettere questo argomento.

Inoltre, non credo che prima di caricare sia il posto giusto per inserire i tuoi iscritti, a meno che tu non stia osservando un evento. Nel tuo caso è meglio spostarlo nel _initSelect()metodo con la chiamata prima parent::_initSelect(). Puoi chiamare il addFilterToMap()metodo all'interno del tuo _initSelect()metodo per risolvere i conflitti di join, in questo modo:

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

Per interesse, perché è meglio eseguire i join in _initSelect ()?
Paul,

@Paul _initSelectviene eseguito solo una volta in ogni momento, _beforeLoadpuò essere chiamato più di una volta, poiché è possibile load()raccogliere più di una volta se si reimposta il suo stato.
Ivan Chepurnyi,

Anche @Paul, poiché _beforeLoad può essere chiamato due volte, riceverai un errore irreversibile da Zend_Db_Select alla seconda chiamata.
Ivan Chepurnyi,

2
Ho fatto qualcosa del genere: $collection = Mage::getModel("education/ticket") ->getCollection() ->addFilterToMap('updated_at', 'main_table.updated_at') ->addFilterToMap('created_at', 'main_table.created_at');
FosAvance

@IvanChepurnyi, sono geniali. Riflette che sei eccellente come architetto Magento 1
Amit Bera
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.