Проблема с использованием «иметь» в коллекции Magento

20

Я пытаюсь создать собственную коллекцию для сетки в модуле администрирования Magento. Я создал новый метод коллекции под названием «addAttributeHaving», который просто делает следующее:

public function addAttributeHaving($value)
{
    $this->getSelect()->having($value);
    return $this;
}

Смотрите коллекционный код:

$collection->addFieldToSelect(
    array(
        'entity_id',
        'created_at',
        'increment_id',
        'customer_email',
        'customer_firstname',
        'customer_lastname',
        'grand_total',
        'status'
    )
);

$collection->getSelect()->joinLeft(array('sfop' => 'sales_flat_order_payment'), 'main_table.entity_id = sfop.parent_id', 'sfop.amount_authorized');
$collection->getSelect()->columns('sum(sfop.amount_authorized) AS AUTHD');
$collection->getSelect()->columns('grand_total - sum(sfop.amount_authorized) AS DIF_AU');
$collection->addFieldToFilter('main_table.state', array('in' => array('new','payment_review')));
$collection->addFieldToFilter('main_table.sd_order_type', array('neq' => 7));
$collection->addFieldToFilter('sfop.method', array('neq' => 'giftcard'));
$collection->addFieldToFilter('main_table.created_at', array('gt' => $this->getFilterDate()));
$collection->getSelect()->group(array('main_table.entity_id'));
$collection->addAttributeHaving('DIF_AU <> 0');
$collection->load(true,true);

$this->setCollection($collection);

Это приводит к следующему SQL, который прекрасно работает и дает ожидаемые результаты при запуске вне Magento.

[METHOD=Varien_Data_Collection_Db->printLogQuery] SELECT `main_table`.`entity_id`, `main_table`.`entity_id`, `main_table`.`created_at`, `main_table`.`increment_id`, `main_table`.`customer_email`, `main_table`.`customer_firstname`, `main_table`.`customer_lastname`, `main_table`.`grand_total`, `main_table`.`status`, `sfop`.`amount_authorized`, sum(sfop.amount_authorized) AS `AUTHD`, grand_total - sum(sfop.amount_authorized) AS `DIF_AU` FROM `sales_flat_order` AS `main_table` LEFT JOIN `sales_flat_order_payment` AS `sfop` ON main_table.entity_id = sfop.parent_id WHERE (main_table.state in ('new', 'payment_review')) AND (main_table.sd_order_type != 7) AND (sfop.method != 'giftcard') AND (main_table.created_at > '2013-04-07') GROUP BY `main_table`.`entity_id` HAVING (DIF_AU <> 0)

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

SQLSTATE [42S22]: Столбец не найден: 1054 Неизвестный столбец «DIF_AU» в «имеющем предложении»

Кроме того, если я удаляю предложение has (которое нарушает мои результаты), я могу использовать столбец DIF_AU для источника данных в Grid.

Энтони Лич младший
источник
1
ОБНОВЛЕНИЕ: я смог отследить проблему до родительского метода getSelectCountSql (). Это на самом деле, где проблема возникает при попытке получить количество сбора.
Энтони Лич младший
1
Опубликовать ответ! С чего это sd_order_type?
отметки
1
Совершенно секретный материал типа пользовательского заказа, который был добавлен к плоским столам. Я все еще работаю над ответом.
Энтони Лич младший
1
«Пользователи с менее чем 10 репутацией не могут ответить на свой вопрос в течение 8 часов после запроса. Вы можете ответить в течение 7 часов. До этого используйте комментарии или измените свой вопрос». (решение прийти через 7 часов).
Энтони Лич младший
1
Кто-то дал этому человеку возражение
отметки

Ответы:

12

Я собираюсь фактически ответить на свой вопрос здесь. Я знаю, безвкусно, но я наткнулся на ответ, глядя гораздо ближе на фактическую трассировку стека. Коллекция загружается нормально, однако сбой происходит немного позже при выполнении, когда мы пытаемся получить счетчик коллекции в Varien_Data_Collection_Db :: getSelectCountSql () . SQL, который получается из этого:

SELECT COUNT(*) FROM sales_flat_order AS main_table LEFT JOIN sales_flat_order_payment AS sfop ON main_table.entity_id = sfop.parent_id WHERE (main_table.state in ('payment_review')) AND (main_table.sd_order_type != 7) AND (sfop.method != 'giftcard') AND (main_table.created_at > '2013-04-07') GROUP BY main_table.entity_id HAVING (DIF_AU <> 0)

Вы заметите, что оператор HAVING присоединен, но у нас больше нет определения для столбца DIF_AU. Похоже, мне нужно расширить пользовательский getSelectCountSql () в моем классе коллекции, чтобы получить правильное количество записей.

Я создал расширенный метод getSelectCountSql () в пользовательском классе коллекции, который добавляет обратно в отсутствующий столбец, необходимый для оператора using.


public function getSelectCountSql()
  {
    $countSelect = parent::getSelectCountSql();
    $countSelect->columns('grand_total - sum(sfop.amount_authorized) AS DIF_AU');
    $countSelect->reset(Zend_Db_Select::GROUP);
    return $countSelect;
  }
Энтони Лич младший
источник
1
Совсем не придирчивый… если вы сначала найдете решение, это поощряется. Другие потенциально найдут это полезным в будущем. +1 :)
Давидгер
Вы должны подать отчет об ошибке! magentocommerce.com/bug-tracking
тесты
Это проблема, которую я также видел, и хорошо поработал над поиском ответа. Однако я не думаю, что ваше решение является правильным - поскольку вы используете group by, ваш SelectCountSql должен возвращать количество групп. Так что вам нужно либо считать (fetchAll ()), либо переписать ваш запрос, используя count(distinct main_table.entity_id)вместоcount(*)
Benubird
Я думаю, что вы, скорее всего, правы. Этот проект был на заднем плане с момента этой публикации, и только сейчас возвращаюсь к нему. На демонстрации на прошлой неделе я заметил, что в сетке сообщается неверное количество записей. Я сообщу о моих результатах, как только я решу это.
Энтони Лич младший
@AnthonyLeachJr какие-нибудь новости о ваших выводах?
Саймон
0

Прежде всего, $countSelect->reset(Zend_Db_Select::HAVING);это означает, что он будет сброшен HAVINGиз вашей коллекции. Это означает, что это удалит пункт, имеющий. И это не то, что вы хотите. Вы можете добавить его в коллекцию ( app/code/core/Mage/Catalog/Model/Resource/Product/Collection.php->_getSelectCountSql()здесь.)

Но главный виновник это getSize()метод, который существует в lib/Varien/Data/Collection/Db.phpфайле.

Я попробовал вышеупомянутое решение, упомянутое @Anthony, но это не сработало.

Теперь я сделал ниже.

public function getSize()
{
    if (is_null($this->_totalRecords)) {
        //$sql = $this->getSelectCountSql();
        $sql = $this->getSelect();
        $this->_totalRecords = count($this->getConnection()->fetchAll($sql, $this->_bindParams));
    }
    return intval($this->_totalRecords);
}

Проверьте, я даже не использую getSelectCountSql(). Я просто читать весь SQL - запрос и выборку всех данных и возвращает количество его. Это все.

Кингшук Деб
источник
0

Я исправил эту проблему здесь: app / code / core / Mage / Catalog / Model / Resource / Product / Collection.php: 943 добавьте это: $ select-> reset (Zend_Db_Select :: HAVING);

Просто скопируйте app / code / core / Mage / Catalog / Model / Resource / Product / Collection.php в app / code / local / Mage / Catalog / Model / Resource / Product / Collection.php

Мой код теперь выглядит так:

/**
 * Build clear select
 *
 * @param Varien_Db_Select $select
 * @return Varien_Db_Select
 */
protected function _buildClearSelect($select = null)
{
    if (is_null($select)) {
        $select = clone $this->getSelect();
    }
    $select->reset(Zend_Db_Select::ORDER);
    $select->reset(Zend_Db_Select::LIMIT_COUNT);
    $select->reset(Zend_Db_Select::LIMIT_OFFSET);
    $select->reset(Zend_Db_Select::COLUMNS);
    $select->reset(Zend_Db_Select::HAVING);
Андрей К
источник
0

Это решение будет работать, если ваш выбор имеет уникальные имена столбцов, потому что любые столбцы в списке выбора подзапроса должны иметь уникальные имена

Подзапрос: подзапрос таблицы позволяет дублировать имена столбцов

public function getSelectCountSql()
{
    $this->_renderFilters();
    $select = clone $this->getSelect();
    $select->reset(Zend_Db_Select::ORDER);
    $select->reset(Zend_Db_Select::LIMIT_COUNT);
    $select->reset(Zend_Db_Select::LIMIT_OFFSET);        

    $countSelect = clone $this->getSelect();
    $countSelect->reset();
    $countSelect->from(array('a' => $select), 'COUNT(*)');
    return $countSelect;
}

PS: Этот ответ для общих коллекций magento. не относится только к коллекции продуктов.

Минеш Патель
источник
0

Это работает

public function getSize () {if (is_null ($ this -> _ totalRecords)) {// $ sql = $ this-> getSelectCountSql (); $ sql = $ this-> getSelect (); $ this -> _ totalRecords = count ($ this-> getConnection () -> fetchAll ($ sql, $ this -> _ bindParams)); } return intval ($ this -> _ totalRecords); }

Джинеш Патель
источник