Conflicto en cláusula where con nombres de columna ambiguos

28

Un poco de contexto para esto. Quiero ampliar la función de exportación de pedidos de ventas (a través de la cuadrícula) para tener más columnas. He creado un módulo que agrega una nueva cuadrícula para exportar y también un nuevo modelo de colección que extiende el original. Esto usa la función _beforeLoad () para poder unirme a las tablas que necesito.

El problema que estoy teniendo es que cuando se agregan los filtros de la cuadrícula (el increment_id, la fecha del pedido, etc.), la cláusula where que agrega no antepone la tabla y obtengo problemas con nombres de columna ambiguos. Por ejemplo, en increment_id tengo el problema en la cláusula 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`

Esta cláusula where se agrega antes de hacer las uniones a las otras tablas en la función _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;
    }

Como breve prueba, cambié la línea a

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

y esto funcionó pero no se siente una excelente manera de hacerlo.

Mi código en _beforeLoad () es

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

Tengo que usar increment_id para unir la tabla de cuadrícula de pedidos de ventas y la tabla de transacciones de SagePay, ya que esa es la única ID común que puedo ver.

Básicamente me pregunto cuál es el mejor enfoque para abordar esto. Probablemente podría salir adelante haciendo el cambio que mencioné anteriormente, pero no me parece correcto. ¿Hay algo que pueda cambiar en mis declaraciones de unión?

Gracias.

Paul
fuente
1
¿Cómo te uniste a las mesas? Trabajar en el modelo Zend_Db_Select es una mala idea, porque magento registra las tablas conjuntas y agrega normalmente todos los prefijos. Escribí un artículo de blog sobre unirse, tal vez ayuda: blog.fabian-blechschmidt.de/articles/…
Fabian Blechschmidt
Gracias por la respuesta, tendré una lectura de eso. Traté de usar joinTable () pero no estaba disponible en el modelo de colección.
Paul

Respuestas:

52

Puede resolver fácilmente cualquier condición de ambigüedad utilizando el siguiente método de recopilación:

  • addFilterToMap($filterName, $alias, $group = 'fields')
    • $filter- es el nombre del filtro que se usa en el addFieldToFilter()método, para su caso esincrement_id
    • $alias- es el nombre completo de la columna asociada al filtro, para su caso lo es main_table.increment_id.
    • $group - estaba destinado a ser un mapa para cualquier tipo de información en la colección, pero por ahora solo se usa en filtros, por lo que puede omitir este argumento.

Además, no creo que beforeLoad sea el lugar adecuado para colocar sus uniones, a menos que esté observando un evento. En su caso, es mejor pasarlo al _initSelect()método con llamadas anteriores parent::_initSelect(). Puede llamar al addFilterToMap()método dentro de su _initSelect()método para resolver conflictos de unión, como este:

$this->addFilterToMap('increment_id', 'main_table.increment_id');
Ivan Chepurnyi
fuente
Por interés, ¿por qué es mejor hacer las uniones en _initSelect ()?
Paul
@Paul _initSelectse ejecuta solo una vez todo el tiempo, _beforeLoadse puede llamar más de una vez, ya que puede load()recopilar más de una vez si restablece su estado.
Ivan Chepurnyi
@Paul también, dado que _beforeLoad puede ser llamado dos veces, recibirá un error fatal de Zend_Db_Select en la segunda llamada.
Ivan Chepurnyi
2
Hice algo así: $collection = Mage::getModel("education/ticket") ->getCollection() ->addFilterToMap('updated_at', 'main_table.updated_at') ->addFilterToMap('created_at', 'main_table.created_at');
FosAvance
@IvanChepurnyi, son geniales. Refleja que eres excelente como arquitecto de Magento 1
Amit Bera