Diferencia entre getSize () y count () en la colección

82

He escuchado muchas veces que ambos son iguales. Pero me enfrento a un problema extraño, en la colección de productos del módulo CatalogSearch, count () devuelve el recuento de producto correcto mientras getSize () devuelve cero.

Entonces, básicamente esto es lo que estoy obteniendo:

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

Pero quiero que getSize () tenga el recuento correcto, ya que decide si mostrar la paginación y los productos en la página de búsqueda o no. Estoy usando Inner Join, Left Join y Where solo en la colección para ser más específico.

¿Alguna idea de por qué tengo este problema extraño?

Gracias

ACTUALIZAR:

Mi pregunta anterior, ¿Cómo clonar la colección en Magento? Quería realizar dos operaciones diferentes en una colección. La primera colección muestra getSize () correcto, pero luego si getSize () es cero, eliminé la cláusula WHERE y le di una nueva condición WHERE. Después de esto, obtengo el SQL bruto correcto de lo que esperaba, y ejecutarlo en MySQL también proporciona un conjunto correcto de registros, pero solo getSize () en la colección está dando cero recuentos.

Básicamente, es posible que deba volver a cargar la colección, ya que getSize () está tomando el conteo anterior. ¿Tiene sentido?

MagExt
fuente

Respuestas:

84

La mayoría (si no todas) las colecciones se extienden Varien_Data_Collection_Db. Aquí están los 2 métodos de esta clase.

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

Hay una diferencia. Para getSize()la colección no se carga. Pues count()lo es. Por lo general, los modelos de colección usan el mismo getSize()método que el anterior y solo anulan getSelectCountSql().
En getSelectCountSql()el límite se restablece para obtener el número total de registros disponibles para los filtros establecidos ( wheredeclaración). Mira cómo getSelectCountSql()funciona

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
fuente
3
¡Excelente! Entonces, ¿cuál debería ser mi próximo paso para volver a cargar la colección para que pueda ser correcta getSize()? ¡Gracias!
MagExt
Sinceramente, no sé por qué obtienes este resultado. En el CatalogSearchmódulo no hay nada que anule getSize()o getSelectCountSql(). Debería funcionar de manera predeterminada, a menos que haya agregado un código personalizado. ¿Puedes publicar la forma en que construyes la colección?
Marius
actualizado la pregunta
MagExt
3
No hay forma de reiniciar _totalRecords. Puede intentar clonar la colección antes de llamar getSize()a la colección original. Quizás eso funcione.
Marius
también puede hacer algo como esto para obtener un recuento de "reinicio":$sql = $collection->getSelectCountSql(); return $collection->getConnection()->fetchOne($sql);
koosa
14

Ten cuidado. Esto es correcto, pero los métodos se sobrescriben Varien_Data_Collection_Dbsegún lo descrito por Marius

Solo echa un vistazo a

// \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);
}

Por lo tanto, en este nivel bajo debería ser el mismo. Ambos métodos cargan la colección y cuentan los artículos.

ACTUALIZAR

Oh, veo un problema: getSize () almacena en caché los _totalRecords, esto significa que no se recalcula. ¿Comprobar dónde _totalRecordsestá configurado?

Fabian Blechschmidt
fuente
Sí, lo he mirado, pero no puedo entender por qué ambos generan conteos diferentes para la misma colección. ¿Alguna idea de cómo volver a cargar la colección o algo para contar correctamente getSize()?
MagExt
actualizó la entrada
Fabian Blechschmidt
1
getSize()no carga la colección de registros que provienen de la base de datos. No, a menos que anule el método y le diga que cargue la colección.
Marius
_totalRecords está protegido, así que no puedo llamarlo en mi archivo personalizado con colección. echo count($collection->load()->getItems());da la cuenta correcta, pero nuevamente quiero getSize()trabajar.
MagExt
5

Esta respuesta aparece en google para "magento getSize incorrecto" y búsquedas similares, por lo que me gustaría agregar un posible escenario que podría ser útil para alguien

Cuando tiene una declaración de grupo en su consulta y hace un

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

Mysql devolverá un recuento para CADA grupo, por lo que Varien_Data_Collection_Db :: getSize () devolverá la respuesta incorrecta, esto se debe a que esta función busca la primera fila:

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

Cuando se llena

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

Selecciona la primera fila y, por lo tanto, devuelve el total del primer grupo como el tamaño total.

Terminé creando este código para contar, basado en los valores únicos de los atributos en mi consulta.

$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);
changeling
fuente
2

En caso de que termines aquí, hay otra solución simple para probar:

System -> Index Management

y selecciónelos todos (incluso si están indicando "Verde, no es necesario volver a indexar" y obligarlos a reindexar).

Esto resolvió mi getSize()problema vacío , que a su vez, permitió que las solicitudes de bases de datos especiales y nuevas encontraran los productos, cumplieran las condiciones "si" y se procesaran correctamente.

BVRoc
fuente
0

Cuando count($collection)era diferente de lo $collection->getSize()que tenía para reindexlos productos, entonces todo funcionó bien.

Zsolti
fuente
-1

Hay una diferencia principal Para getSize () la colección de productos no está cargada. Para count () cargará toda la colección de productos. Por lo tanto, para grandes catálogos no es aconsejable utilizar la función de conteo en ninguna colección.

Nayan Baraiya
fuente
Ya lo dije en Marius post ...
sv3n