DDC-3104: Invalid count on EXTRA LAZY collection of SINGLE TABLE entities #3855

Open
opened 2026-01-22 14:29:09 +01:00 by admin · 9 comments
Owner

Originally created by @doctrinebot on GitHub (Apr 28, 2014).

Originally assigned to: @beberlei on GitHub.

Jira issue originally created by user deatheriam:

* @ORM\Entity
 * @ORM\InheritanceType("SINGLE_TABLE")
 * @ORM\Table(name="entity_promotion")
 * @ORM\DiscriminatorColumn(name="type", type="string")
 * @ORM\DiscriminatorMap({
 *     "brand"           = "BrandPromotion",
 *     "category"        = "CategoryPromotion",
 * })
 */
abstract class EntityPromotionAbstract

**** CategoryPromotion entity:

 * @ORM\Entity
 */
class CategoryPromotion extends EntityPromotionAbstract
{
    /****
     * Category
     *
     * @var Category
     * @ORM\ManyToOne(targetEntity="Category", inversedBy="CategoryPromotions")
     * @ORM\JoinColumn(name="instance*id", referencedColumnName="category*id")
     */
    protected $Category;
...
}

**** BrandPromotion entity:

 * @ORM\Entity
 */
class BrandPromotion extends EntityPromotionAbstract
{
    /****
     * Brand
     *
     * @var Brand
     * @ORM\ManyToOne(targetEntity="Brand", inversedBy="BrandPromotions")
     * @ORM\JoinColumn(name="instance*id", referencedColumnName="brand*id")
     */
    protected $Brand;
}

**** Brand entity:

    /****
     * Associated BrandPromotions
     *
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="BrandPromotion", mappedBy="Brand", fetch="EXTRA_LAZY")
     */
    protected $BrandPromotions;

**** Category entity:

    /****
     * Associated CategoryPromotions
     *
     * @var \Doctrine\Common\Collections\ArrayCollection|\Doctrine\ORM\PersistentCollection
     *
     * @ORM\OneToMany(targetEntity="CategoryPromotion", mappedBy="Category", fetch="EXTRA_LAZY")
     */
    protected $CategoryPromotions;
  • When Brand::BrandPromotions collection is not initialized, calling count on it will return a count of BrandPromotion and CategoryPromotion elements, but calling isEmpty will return a count of BrandPromotion entities only.
  • \Doctrine\ORM\Persisters\OneToManyPersister::count does not take into account a discriminator value of 'brand':
        foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] as $joinColumn) {
            $whereClauses[] = $joinColumn['name'] . ' = ?';

            $params[] = ($targetClass->containsForeignIdentifier)
                ? $id[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])]
                : $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]];
        }

  • This results in a query:
SELECT count(*) FROM entity*promotion t WHERE instance*id = ?
  • The query should include a type condition:
SELECT count(*) FROM entity*promotion t WHERE instance*id = ? AND (t.type in 'brand')
Originally created by @doctrinebot on GitHub (Apr 28, 2014). Originally assigned to: @beberlei on GitHub. Jira issue originally created by user deatheriam: - This issue relates to http://www.doctrine-project.org/jira/browse/[DDC-1595](http://www.doctrine-project.org/jira/browse/DDC-1595) - With the following entities ***\* EntityPromotionAbstract entity: ``` * @ORM\Entity * @ORM\InheritanceType("SINGLE_TABLE") * @ORM\Table(name="entity_promotion") * @ORM\DiscriminatorColumn(name="type", type="string") * @ORM\DiscriminatorMap({ * "brand" = "BrandPromotion", * "category" = "CategoryPromotion", * }) */ abstract class EntityPromotionAbstract ``` ***\* CategoryPromotion entity: ``` * @ORM\Entity */ class CategoryPromotion extends EntityPromotionAbstract { /**** * Category * * @var Category * @ORM\ManyToOne(targetEntity="Category", inversedBy="CategoryPromotions") * @ORM\JoinColumn(name="instance*id", referencedColumnName="category*id") */ protected $Category; ... } ``` ***\* BrandPromotion entity: ``` * @ORM\Entity */ class BrandPromotion extends EntityPromotionAbstract { /**** * Brand * * @var Brand * @ORM\ManyToOne(targetEntity="Brand", inversedBy="BrandPromotions") * @ORM\JoinColumn(name="instance*id", referencedColumnName="brand*id") */ protected $Brand; } ``` ***\* Brand entity: ``` /**** * Associated BrandPromotions * * @var \Doctrine\Common\Collections\Collection * * @ORM\OneToMany(targetEntity="BrandPromotion", mappedBy="Brand", fetch="EXTRA_LAZY") */ protected $BrandPromotions; ``` ***\* Category entity: ``` /**** * Associated CategoryPromotions * * @var \Doctrine\Common\Collections\ArrayCollection|\Doctrine\ORM\PersistentCollection * * @ORM\OneToMany(targetEntity="CategoryPromotion", mappedBy="Category", fetch="EXTRA_LAZY") */ protected $CategoryPromotions; ``` - When Brand::BrandPromotions collection is not initialized, calling count on it will return a count of BrandPromotion and CategoryPromotion elements, but calling isEmpty will return a count of BrandPromotion entities only. - \Doctrine\ORM\Persisters\OneToManyPersister::count does not take into account a discriminator value of 'brand': ``` foreach ($targetClass->associationMappings[$mapping['mappedBy']]['joinColumns'] as $joinColumn) { $whereClauses[] = $joinColumn['name'] . ' = ?'; $params[] = ($targetClass->containsForeignIdentifier) ? $id[$sourceClass->getFieldForColumn($joinColumn['referencedColumnName'])] : $id[$sourceClass->fieldNames[$joinColumn['referencedColumnName']]]; } ``` - This results in a query: ``` SELECT count(*) FROM entity*promotion t WHERE instance*id = ? ``` - The query should include a type condition: ``` SELECT count(*) FROM entity*promotion t WHERE instance*id = ? AND (t.type in 'brand') ```
admin added the Bug label 2026-01-22 14:29:09 +01:00
Author
Owner

@doctrinebot commented on GitHub (Apr 28, 2014):

@doctrinebot commented on GitHub (Apr 28, 2014): - relates to [DDC-1595: Wrong count in relation with inheritance](http://www.doctrine-project.org/jira/browse/DDC-1595)
Author
Owner

@doctrinebot commented on GitHub (Apr 29, 2014):

Comment created by @ocramius:

Why would the query include a type conditional? To me, it seems like the association was built between invalid data types instead.

@doctrinebot commented on GitHub (Apr 29, 2014): Comment created by @ocramius: Why would the query include a type conditional? To me, it seems like the association was built between invalid data types instead.
Author
Owner

@doctrinebot commented on GitHub (May 6, 2014):

Comment created by deatheriam:

  • Could you elaborate on what exactly you mean when you are saying, that the association was built between invalid data types?
  • Even if your statement is valid, then why calling on a initialized collection $collection->isEmpty() produces a correct result? Calling $collection->count() produces also a correct result on an initialized collection, wheres calling $collection->count() on an unitialized collection results in an invalid element count.
@doctrinebot commented on GitHub (May 6, 2014): Comment created by deatheriam: - Could you elaborate on what exactly you mean when you are saying, that the association was built between invalid data types? - Even if your statement is valid, then why calling on a initialized collection $collection->isEmpty() produces a correct result? Calling $collection->count() produces also a correct result on an initialized collection, wheres calling $collection->count() on an unitialized collection results in an invalid element count.
Author
Owner

@doctrinebot commented on GitHub (May 6, 2014):

Comment created by @ocramius:

Ah, I see what you mean now. Sorry, I was confusing this with a joined table inheritance.

@doctrinebot commented on GitHub (May 6, 2014): Comment created by @ocramius: Ah, I see what you mean now. Sorry, I was confusing this with a joined table inheritance.
Author
Owner

@doctrinebot commented on GitHub (May 20, 2014):

Comment created by vigintas:

Exactly same behaviour just wasted me a few hours. Shame I'll have to switch fetch mode back to LAZY until this gets fixed.

@doctrinebot commented on GitHub (May 20, 2014): Comment created by vigintas: Exactly same behaviour just wasted me a few hours. Shame I'll have to switch fetch mode back to LAZY until this gets fixed.
Author
Owner

@liverbool commented on GitHub (Mar 22, 2017):

How about status of this?

@liverbool commented on GitHub (Mar 22, 2017): How about status of this?
Author
Owner

@Ocramius commented on GitHub (Mar 22, 2017):

@liverbool consider providing a test case

@Ocramius commented on GitHub (Mar 22, 2017): @liverbool consider providing a test case
Author
Owner

@liverbool commented on GitHub (Mar 22, 2017):

Seem collection filter doesn't use COUNT query.

$this->collection->filter(function($object) use ($refId) {
    return $object->getId() === $refId;
})->count();
@liverbool commented on GitHub (Mar 22, 2017): Seem collection filter doesn't use `COUNT` query. ```php $this->collection->filter(function($object) use ($refId) { return $object->getId() === $refId; })->count(); ```
Author
Owner

@lcobucci commented on GitHub (Mar 23, 2017):

@liverbool that's not exactly a test case though, you can use 1aa02f9afc/tests/Doctrine/Tests/ORM/Functional/Ticket/GH5762Test.php as example

@lcobucci commented on GitHub (Mar 23, 2017): @liverbool that's not exactly a test case though, you can use https://github.com/doctrine/doctrine2/blob/1aa02f9afcb374d7d3060f960fa8ce096bf71369/tests/Doctrine/Tests/ORM/Functional/Ticket/GH5762Test.php as example
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#3855