Różnica między getSize () a count () w kolekcji

81

Wiele razy słyszałem, że oba są takie same. Ale mam do czynienia z dziwnym problemem: w kolekcji produktów modułu CatalogSearch count () zwraca poprawną liczbę produktów, a getSize () zwraca zero.

Zasadniczo oto, co otrzymuję:

$collection->count(); //correct count
$collection->getSize(); //0

Ale chcę, aby getSize () miał poprawną liczbę, ponieważ decyduje, czy wyświetlać paginację i produkty na stronie wyszukiwania, czy nie. Używam warunku łączenia wewnętrznego, łączenia lewego i Where tylko w kolekcji, aby być bardziej szczegółowym.

Jakieś pomysły, dlaczego mam ten dziwny problem?

Dzięki

AKTUALIZACJA:

Moje poprzednie pytanie: Jak sklonować kolekcję w Magento? Chciałem wykonać dwie różne operacje na jednej kolekcji. Pierwsza kolekcja pokazuje poprawną metodę getSize (), ale jeśli wartość getSize () wynosi zero, usunąłem klauzulę WHERE i podałem nowy warunek WHERE. Następnie otrzymuję poprawny nieprzetworzony kod SQL, czego się spodziewałem, a uruchomienie go w MySQL daje również prawidłowy zestaw rekordów, ale tylko getSize () w kolekcji daje zerową liczbę.

Zasadniczo więc może być konieczne ponowne załadowanie kolekcji, ponieważ metoda getSize () stara się liczyć. Ma sens?

MagExt
źródło

Odpowiedzi:

83

Większość (jeśli nie wszystkie) kolekcji jest rozszerzana Varien_Data_Collection_Db. Oto 2 metody z tej klasy

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

public function count() //inherited from Varien_Data_Collection
{
    $this->load();
    return count($this->_items);
}

Jest różnica. Do getSize()kolekcji nie jest załadowany. Bo count()tak jest. Zwykle modele kolekcji używają tej samej getSize()metody jak powyżej i tylko zastępują getSelectCountSql().
W getSelectCountSql()limicie jest resetowany w celu uzyskania całkowitej liczby rekordów dostępnych dla ustawionych filtrów ( whereinstrukcja). Zobacz jak getSelectCountSql()działa

public function getSelectCountSql()
{
    $this->_renderFilters();
    $countSelect = clone $this->getSelect();
    $countSelect->reset(Zend_Db_Select::ORDER);
    $countSelect->reset(Zend_Db_Select::LIMIT_COUNT);
    $countSelect->reset(Zend_Db_Select::LIMIT_OFFSET);
    $countSelect->reset(Zend_Db_Select::COLUMNS);
    $countSelect->columns('COUNT(*)');
    return $countSelect;
} 
Marius
źródło
3
Wspaniały! Więc jaki powinien być mój następny krok, aby ponownie załadować kolekcję, aby mogła być poprawna getSize()? Dzięki!
MagExt
Naprawdę nie wiem, dlaczego otrzymujesz ten wynik. W CatalogSearchmodule nie ma nic, co nadpisuje getSize()lub getSelectCountSql(). Powinno działać domyślnie, chyba że dodasz niestandardowy kod. Czy możesz opublikować sposób budowania kolekcji?
Marius
zaktualizowałem pytanie.
MagExt
3
Nie ma możliwości zresetowania _totalRecords. Możesz spróbować sklonować kolekcję przed wywołaniem getSize()oryginalnej kolekcji. Może to zadziała.
Marius
możesz również zrobić coś takiego, aby uzyskać liczbę „resetowania”:$sql = $collection->getSelectCountSql(); return $collection->getConnection()->fetchOne($sql);
koosa,
14

Bądź ostrożny. To prawda, ale metody są nadpisywane Varien_Data_Collection_Dbzgodnie z opisem Mariusza

Spójrz tylko

// \Varien_Data_Collection::getSize
public function getSize()
{
    $this->load();
    if (is_null($this->_totalRecords)) {
        $this->_totalRecords = count($this->getItems());
    }
    return intval($this->_totalRecords);
}

// \Varien_Data_Collection::count
public function count()
{
    $this->load();
    return count($this->_items);
}

Tak powinno być na tym niskim poziomie. Obie metody ładują kolekcję i liczą elementy.

AKTUALIZACJA

Och, widzę problem: getSize () buforuje _totalRecords, co oznacza, że ​​nie jest on ponownie obliczany. Sprawdź, gdzie _totalRecordsjest ustawiony?

Fabian Blechschmidt
źródło
Tak, przyjrzałem się temu, ale nie mogę zrozumieć, dlaczego oba generują różne liczby dla tej samej kolekcji? Jakieś pomysły, jak ponownie załadować kolekcję lub coś, aby uzyskać prawidłowe liczenie getSize()?
MagExt
zaktualizował wpis
Fabian Blechschmidt
1
getSize()nie ładuje kolekcji rekordów pochodzących z bazy danych. Nie, chyba że przesłonisz metodę i powiesz jej, aby załadowała kolekcję.
Marius
_totalRecords jest chroniony, więc nie mogę wywołać go w moim niestandardowym pliku z kolekcją. echo count($collection->load()->getItems());daje prawidłową liczbę, ale znowu chcę getSize()pracować.
MagExt
5

Ta odpowiedź pojawia się w Google dla „magento getSize źle” i podobnych wyszukiwań, więc chciałbym dodać możliwy scenariusz, który może być przydatny dla kogoś

Kiedy masz zapytanie grupowe w swoim zapytaniu i robisz

SELECT COUNT(DISTINCT e.entity_id) ... GROUP BY ( at_id_art.value )

Mysql zwróci liczbę dla KAŻDEJ grupy, więc Varien_Data_Collection_Db :: getSize () zwróci złą odpowiedź, ponieważ funkcja ta pobiera pierwszy wiersz:

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

Kiedy się zapełni

$this->_totalRecords = $this->getConnection()->fetchOne($sql, $this->_bindParams);

Wybiera pierwszy wiersz i dlatego zwraca sumę pierwszej grupy jako całkowity rozmiar.

Skończyło się na tym, że liczę ten kod na podstawie unikalnych wartości atrybutów w moim zapytaniu.

$select = clone $collection->getSelect();
$group = $select->getPart(Zend_Db_Select::GROUP);
$select->reset(Zend_Db_Select::GROUP)->reset(Zend_Db_Select::COLUMNS)->columns("COUNT(DISTINCT {$group[0]})");
$totalCount = $collection->getConnection()->fetchOne($select);
uzurpator
źródło
2

Na wypadek, gdybyś tu trafił, jest jeszcze jedna prosta poprawka:

System -> Index Management

i zaznacz je wszystkie (nawet jeśli wskazują „Zielony, nie trzeba ponownie indeksować”) i zmusić ich do ponownego indeksowania.

To rozwiązało mój pusty getSize()problem, który z kolei pozwolił Specjalnym i Nowym Żądaniom bazy danych znaleźć produkty, spełnić warunki „jeśli” i poprawnie renderować.

BVRoc
źródło
0

Kiedy count($collection)było inaczej niż $collection->getSize()miałem do reindexproduktów, wtedy wszystko działało dobrze.

Zsolti
źródło
-1

Istnieje główna różnica W przypadku getSize () kolekcja produktów nie jest ładowana. Dla count () załaduje całą kolekcję produktów. Dlatego w przypadku dużego katalogu nie zaleca się używania funkcji liczenia w żadnej kolekcji.

Nayan Baraiya
źródło
Już powiedziałem w Marius post ...
sv3n