doctrine / orm

Doctrine Object Relational Mapper (ORM)
https://www.doctrine-project.org/projects/orm.html
MIT License
9.93k stars 2.52k forks source link

DDC-1918: Paginator gives strange results in the end of the resultset #2586

Closed doctrinebot closed 8 years ago

doctrinebot commented 12 years ago

Jira issue originally created by user alex88:

Hello, i've an image and a tag entities, image has a one to many with tags. I was using limit and offset and it was giving 7 images instead of 9 (limit is set to 9) due one image has 3 tags. So i started using paginator to resolve the join-fetch issue. It worked fine at the beginning of the resultset, the problem is at the end (i have 29 images), when i increase the offset. These are the last 3 calls:

SELECT DISTINCT i0.id AS id0, i0.creation_time AS creationtime1 FROM Image i0 LEFT JOIN Tag t1 ON i0.id = t1.image WHERE i0.owner = 1 ORDER BY i0_.creation_time DESC LIMIT 9 OFFSET 27

it returns 2 images, correct, so the final query is

SELECT i0.id AS id0, i0.name AS name1, i0.status AS status2, i0.last_processing AS lastprocessing3, i0.creation_time AS creationtime4, i0.height AS height5, i0.width AS width6, i0.layers AS layers7, i0.foldersize AS foldersize8, i0.sourcesize AS sourcesize9, i0.title AS title10, i0.description AS description11, i0.originalUrl AS originalUrl12, i0.private AS private13, i0.watermark AS watermark14, i0.favorite AS favorite15, t1.id AS id16, t1.tag AS tag17, i0.owner AS owner18, t1.image AS image19 FROM Image i0 LEFT JOIN Tag t1 ON i0.id = t1.image WHERE i0.owner = 1 AND i0.id IN (?, ?) ORDER BY i0_.creation_time DESC

with parameters the 2 images id, still correct.

SELECT DISTINCT i0.id AS id0, i0.creation_time AS creationtime1 FROM Image i0 LEFT JOIN Tag t1 ON i0.id = t1.image WHERE i0.owner = 1 ORDER BY i0_.creation_time DESC LIMIT 9 OFFSET 29

which doesn't get any result, but it still goes on querying without id filter:

SELECT i0.id AS id0, i0.name AS name1, i0.status AS status2, i0.last_processing AS lastprocessing3, i0.creation_time AS creationtime4, i0.height AS height5, i0.width AS width6, i0.layers AS layers7, i0.foldersize AS foldersize8, i0.sourcesize AS sourcesize9, i0.title AS title10, i0.description AS description11, i0.originalUrl AS originalUrl12, i0.private AS private13, i0.watermark AS watermark14, i0.favorite AS favorite15, t1.id AS id16, t1.tag AS tag17, i0.owner AS owner18, t1.image AS image19 FROM Image i0 LEFT JOIN Tag t1 ON i0.id = t1.image WHERE i0.owner = 1 ORDER BY i0.creation_time DESC LIMIT 9 OFFSET 29

and it gets the last 2 images maybe due the fetch join like as i'm not using paginator.

doctrinebot commented 12 years ago

Comment created by alex88:

No updates?

doctrinebot commented 12 years ago

Comment created by @beberlei:

Sorry I am swamped with work at the moment and other important projects, I couldnt look into it yet.

doctrinebot commented 12 years ago

Comment created by alex88:

Commenting the if this part:

            // don't do this for an empty id array
            //if (count($ids) > 0) {
                $namespace = WhereInWalker::PAGINATOR*ID*ALIAS;

                $whereInQuery->setHint(Query::HINT*CUSTOM_TREE*WALKERS, array('Doctrine\ORM\Tools\Pagination\WhereInWalker'));
                $whereInQuery->setHint(WhereInWalker::HINT*PAGINATOR_ID*COUNT, count($ids));
                $whereInQuery->setFirstResult(null)->setMaxResults(null);
                foreach ($ids as $i => $id) {
                    $i<ins></ins>;
                    $whereInQuery->setParameter("{$namespace}_{$i}", $id);
                }
            //}

make it works, for me is better, because if you don't have results to show as the result of the select distinct is empty you shouldn't have any result at all. Because if you don't add the "WHERE IN" query you get the results joined with no difference between using or not the paginator.

doctrinebot commented 12 years ago

Comment created by @beberlei:

This is weird, an empty IN() normally produces an error. We could add a non matching condition instead, like 0 = 1.

doctrinebot commented 12 years ago

Comment created by alex88:

Not really, in my case (mysql) it creates the following query:

SELECT i0.id AS id0, i0.name AS name1, i0.status AS status2, i0.last_processing AS lastprocessing3, i0.creation_time AS creationtime4, i0.height AS height5, i0.width AS width6, i0.layers AS layers7, i0.foldersize AS foldersize8, i0.sourcesize AS sourcesize9, i0.title AS title10, i0.description AS description11, i0.originalUrl AS originalUrl12, i0.private AS private13, i0.watermark AS watermark14, i0.favorite AS favorite15, t1.id AS id16, t1.tag AS tag17, i0.owner AS owner18, t1.image AS image19 FROM Image i0 LEFT JOIN Tag t1 ON i0.id = t1.image WHERE i0.owner = 1 AND i0.id IS NULL ORDER BY i0_.creation_time DESC

so it sets "AND i0_.id IS NULL" which solves the problem, the best solution for me is to directly return an empty set if the DISTINCT gives no results.

doctrinebot commented 12 years ago

Comment created by alex88:

Solved with commit bc2476f342ceda98559b87a314806581cf969796

doctrinebot commented 12 years ago

Issue was closed with resolution "Fixed"