Konflikt klauzuli where z niejednoznacznymi nazwami kolumn


28

Trochę kontekstu. Chcę rozszerzyć funkcję eksportu zamówienia sprzedaży (za pośrednictwem siatki), aby mieć więcej kolumn. Stworzyłem moduł, który dodaje nową siatkę do eksportowania, a także nowy model kolekcji, który rozszerza oryginał. Korzysta z funkcji _beforeLoad (), dzięki czemu mogę dołączyć do potrzebnych tabel.

Problem, który mam, polega na tym, że kiedy dodaje się filtry z siatki (increment_id, data zamówienia itp.), Klauzula where dodaje to nie poprzedza tabeli i pojawiają się problemy z niejednoznacznymi nazwami kolumn. Na przykład w increment_id mam problem z klauzulą ​​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`

To, gdzie klauzula jest dodawana przed wykonaniem połączeń do innych tabel w funkcji _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;
    }

Jako krótki test zmieniłem linię na

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

i to zadziałało, ale nie jest to świetny sposób na zrobienie tego.

Mój kod w _beforeLoad () to

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

Muszę użyć increment_id, aby dołączyć do tabeli siatki zamówień sprzedaży i tabeli transakcji SagePay, ponieważ jest to jedyny wspólny identyfikator, jaki widzę.

Zasadniczo zastanawiam się, jakie jest najlepsze podejście do rozwiązania tego problemu. Prawdopodobnie mógłbym uciec od robienia zmiany, o której wspomniałem powyżej, ale to nie wydaje się właściwe. Czy mogę coś zmienić w instrukcjach dołączania?

Dzięki.


1
Jak dołączyłeś do stolików? Praca na modelu Zend_Db_Select jest złym pomysłem, ponieważ magento zapisuje wspólne tabele i zwykle dodaje wszystkie prefiksy. Napisałem artykuł na blogu o dołączaniu, może to pomaga: blog.fabian-blechschmidt.de/articles/…
Fabian Blechschmidt

Dziękuję za odpowiedź, przeczytam o tym. Próbowałem użyć joinTable (), ale nie było ono dostępne w modelu kolekcji.
Paul

Odpowiedzi:


52

Możesz łatwo rozwiązać wszelkie niejednoznaczne warunki, używając następującej metody zbierania:

  • addFilterToMap($filterName, $alias, $group = 'fields')
    • $filter- jest to nazwa filtra używanego w addFieldToFilter()metodzie, w twoim przypadku tak jestincrement_id
    • $alias- jest to pełna nazwa kolumny powiązanej z filtrem, w twoim przypadku tak jest main_table.increment_id.
    • $group - miał być mapą dla wszelkiego rodzaju informacji w kolekcji, ale na razie jest używany tylko w filtrach, więc możesz pominąć ten argument.

Nie sądzę też, aby beforeLoad było właściwym miejscem do umieszczania połączeń, chyba że obserwujesz jakieś zdarzenie. W twoim przypadku lepiej jest przestawić go na _initSelect()metodę z wywołaniem wcześniej parent::_initSelect(). Możesz wywołać addFilterToMap()metodę w swojej _initSelect()metodzie w celu rozwiązania konfliktów łączenia, w następujący sposób:

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

Z braku zainteresowania, dlaczego lepiej jest łączyć złączenia w _initSelect ()?
Paul

@Paul _initSelectjest wykonywany tylko raz przez cały czas, _beforeLoadmożna go wywołać więcej niż jeden raz, ponieważ można load()zbierać więcej niż jeden raz, jeśli zresetujesz jego stan.
Ivan Chepurnyi

@Paul również, ponieważ _beforeLoad można wywołać dwukrotnie, podczas drugiego połączenia otrzymasz błąd krytyczny od Zend_Db_Select.
Ivan Chepurnyi

2
Zrobiłem coś takiego: $collection = Mage::getModel("education/ticket") ->getCollection() ->addFilterToMap('updated_at', 'main_table.updated_at') ->addFilterToMap('created_at', 'main_table.created_at');
FosAvance

@IvanChepurnyi, są genialne. Odzwierciedla to, że jesteś doskonały jako architekt Magento 1
Amit Bera
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.