[РЕШЕНО] ActiveDataProvider и joinWith("hasMany") возвращает меньше моделей, чем задано в pageSize

Общие вопросы по использованию второй версии фреймворка. Если не знаете как что-то сделать и это про Yii 2, вам сюда.
Ответить
chebureque
Сообщения: 9
Зарегистрирован: 2013.01.10, 11:15

[РЕШЕНО] ActiveDataProvider и joinWith("hasMany") возвращает меньше моделей, чем задано в pageSize

Сообщение chebureque »

Тыкните носом, что я упускаю из вида.

Есть модель для поиска AdvertSearch которая возвращает ActiveDataProvider:

Код: Выделить всё

/* app/models/AdvertSearch.php */

$query = Advert::find();
$query->joinWith(['advertLinks', 'advertPhones', 'advertPhotos'])
$dataProvider = new ActiveDataProvider([
    'query' => $query,
    'totalCount' => $query->count('advert.id')
]);

return $dataProvider;
Есть вьюха где я дергаю модели из $dataProvider:

Код: Выделить всё

/* app/views/advert/index.php */

$models = $dataProvider->getModels()
В чем проблема - в базе находится, скажем, 650 записей advert и по идее $dataProvider должен их возвращать по 20 штук на страницу, вот только по факту он возвращает не по 20, а скажем по 14-19, объекте пагинации показывает что все отлично и я должен получать по 20 объектов:

Код: Выделить всё

/* var_dump($dataProvider->getPagination() */

object(yii\data\Pagination)[151]
    public 'pageParam' => string 'page' (length=4)
    public 'pageSizeParam' => string 'per-page' (length=8)
    public 'forcePageParam' => boolean true
    public 'route' => null
    public 'params' => null
    public 'urlManager' => null
    public 'validatePage' => boolean true
    public 'totalCount' => string '650' (length=3)
    public 'defaultPageSize' => int 20
    public 'pageSizeLimit' => 
        array (size=2)
            0 => int 1
            1 => int 50
    private '_pageSize' => int 20
    private '_page' => int 0
Если из запроса убрать joinWith() - все четко. Где копать товарищи?

зы Здесь задавался подобный вопрос, но решать проблему подзапросами как-то не по дзэну.
зыы Проблема наблюдается только если джойнить связи hasMany().
Последний раз редактировалось chebureque 2015.03.22, 01:35, всего редактировалось 1 раз.
astronin
Сообщения: 606
Зарегистрирован: 2012.01.30, 17:46

Re: ActiveDataProvider + joinWith() и getModels()

Сообщение astronin »

многое зависит от select-ов, направления join-ов...
если я правильно понимаю, объект Pagination вам показывает, сколько должно быть записей, а не сколько вернулось
chebureque
Сообщения: 9
Зарегистрирован: 2013.01.10, 11:15

Re: [РЕШЕНО] ActiveDataProvider и joinWith("hasMany") возвращает меньше моделей, чем задано в pageSize

Сообщение chebureque »

Из-за joinWith в результирующей таблице оказывается по несколько строк на одну главную модель.

Код: Выделить всё

/* app/models/Advert.php */
public function getAdvertPhotos()
{
    return $this->hasMany(AdvertPhoto::className(), ['advertId' => 'id']);
}
 
Если у наших моделей Advert есть, скажем, по 10 родственных моделей AdvertPhoto, то при выборке

Код: Выделить всё

/* app/models/AdvertSearch.php */
$dataProvider = new ActiveDataProvider([
    'query' => Advert::find()->joinWith('advertPhotos'),
    'pagination' => ['pageSize' => 20]
]);

return $dataProvider;
в результирующей таблице будет по 10 строк для каждого Advert, содержащих, помимо данных Advert, родственные данные AdvertPhoto. pageSize передается в запросе как LIMIT 20, соответственно мы действительно получаем 20 строк, но уникальных моделей Advert среди этих 20 строк будет всего 2 (и у каждой по 10 родственных моделей AdvertPhoto). По этой же причине totalCount будет нам показывать не число найденных моделей Advert, а кол-во всех записей в результирующей таблице после joinWith.

Решение очень простое, добавляем к нашему запросу инструкцию DISTINCT следующим образом:

Код: Выделить всё

/* app/models/AdvertSearch.php */
$dataProvider = new ActiveDataProvider([
    'query' => Advert::find()->joinWith('advertPhotos')->distinct()
]);

return $dataProvider; 
Ответить