Конфликты в предложении where с неоднозначными именами столбцов

28

Немного контекста для этого. Я хочу расширить функцию экспорта заказа на продажу (через сетку), чтобы иметь больше столбцов. Я создал модуль, который добавляет новую сетку для экспорта, а также новую модель коллекции, которая расширяет оригинал. При этом используется функция _beforeLoad (), поэтому я могу объединить нужные мне таблицы.

Проблема, с которой я столкнулся, заключается в том, что при добавлении фильтров из сетки (increment_id, даты заказа и т. Д.) Добавленное здесь предложение where не ставит префикс таблицы, и у меня возникают проблемы с неоднозначными именами столбцов. Например, на increment_id у меня проблема в предложении 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`

Это условие, где добавляется, прежде чем я сделаю соединения с другими таблицами в функции _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;
    }

В качестве краткого теста я изменил строку на

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

и это сработало, но это не очень хороший способ сделать это.

Мой код в _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();
}

Я должен использовать increment_id для соединения таблицы сетки заказа на продажу и таблицы транзакций SagePay, так как это единственный общий идентификатор, который я вижу.

По сути, мне интересно, что лучший подход для решения этой проблемы. Я мог бы, вероятно, сойти с рук с изменениями, которые я упомянул выше, но это не правильно. Могу ли я что-то изменить в моих заявлениях о присоединении?

Спасибо.

Павел
источник
1
Как ты присоединился к столам? Работа с моделью Zend_Db_Select - плохая идея, потому что magento записывает объединенные таблицы и обычно добавляет все префиксы. Я написал в блоге статью о присоединении, может быть, это поможет: blog.fabian-blechschmidt.de/articles/…
Фабиан Блехшмидт
Спасибо за ответ, я прочитаю это. Я пытался использовать joinTable (), но он не был доступен в модели коллекции.
Пол

Ответы:

52

Вы можете легко разрешить любое неоднозначное условие, используя следующий метод сбора:

  • addFilterToMap($filterName, $alias, $group = 'fields')
    • $filter- это имя фильтра, который используется в addFieldToFilter()методе, для вашего случая этоincrement_id
    • $alias- это полное имя столбца, связанного с фильтром, в вашем случае это так main_table.increment_id.
    • $group - задумывался как карта для любой информации в коллекции, но пока она используется только в фильтрах, поэтому вы можете опустить этот аргумент.

Также я не думаю, что beforeLoad - это подходящее место для размещения ваших объединений, если только вы не наблюдаете событие. В вашем случае лучше перенести его в _initSelect()метод с вызовом ранее parent::_initSelect(). Вы можете вызвать addFilterToMap()метод внутри вашего _initSelect()метода для разрешения конфликтов соединения, например:

$this->addFilterToMap('increment_id', 'main_table.increment_id');
Иван Чепурный
источник
Из интереса, почему лучше делать объединения в _initSelect ()?
Пол
@Paul _initSelectвыполняется только один раз за все время, _beforeLoadможет вызываться более одного раза, так как вы можете load()собирать более одного раза, если вы сбросите его состояние.
Иван Чепурный
@Paul, так как _beforeLoad можно вызывать дважды, вы получите фатальную ошибку от Zend_Db_Select при втором вызове.
Иван Чепурный
2
Я сделал что-то вроде этого: $collection = Mage::getModel("education/ticket") ->getCollection() ->addFilterToMap('updated_at', 'main_table.updated_at') ->addFilterToMap('created_at', 'main_table.created_at');
FosAvance
@IvanChepurnyi, гениальны. Это говорит о том, что вы превосходны как архитектор Magento 1
Амит Бера