Skip to content

[POSSIBLE BUG] setFetchMode not overriding fetch annotation #7860

@yesdevnull

Description

@yesdevnull

Bug Report

Q A
BC Break no
Version 2.6.4

Summary

I have the following entities:

  • IntervalGroup w/ oneToMany relation to IntervalType (fetch: EXTRA_LAZY)
  • IntervalType w/ oneToMany relation to Interval (fetch: EXTRA_LAZY)
  • Interval w/ oneToMany relation to Task (fetch: EAGER)

On the IntervalGroup repository I'm doing a DQL Query Builder query to load all IntervalGroups, and left join IntervalGroup.intervalTypes and intervalTypes.interval.

By default, the Task relation on Interval will be eager-loaded during hydration, however I don't want Tasks in this case. To counter that I'm using setFetchMode() on the Query object like so:

$query->setFetchMode(Interval::class, 'tasks', ClassMetadataInfo::FETCH_LAZY)

Which, as I understand, should prevent the ORM from fetching and hydrating those relations in that query.

Current behavior

Currently, the query hint for the fetch mode is not overriding the fetch mode on the annotation, so Doctrine loads the Interval.tasks relation.

createEntity in the UnitOfWork class is using the fetch value from the annotation, instead of the fetchMode query hint:

// Lines 2859 - 2862 of UnitOfWork.php
if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
    $this->loadCollection($pColl);
    $pColl->takeSnapshot();
}

(as seen here)

When I dump($assoc) I can see for the targetEntity = "Task" that $assoc['fetch'] equals 3 (ClassMetadata::FETCH_EAGER) when I specified in setFetchMode() that it should be 2 (ClassMetadata::FETCH_LAZY).

How to reproduce

class IntervalGroup
{
    /**
     * @ORM\OneToMany(targetEntity="IntervalType", mappedBy="intervalGroup", fetch="EXTRA_LAZY")
     */
    private $intervalTypes;

    public function __construct()
    {
        $this->intervalTypes = new ArrayCollection();
    }
}
class IntervalType
{
    /**
     * @ORM\ManyToOne(targetEntity="IntervalGroup", inversedBy="intervalTypes", fetch="EAGER")
     * @ORM\JoinColumn(name="interval_group_id", referencedColumnName="id", nullable=true)
     */
    private $intervalGroup;

    /**
     * @ORM\OneToMany(targetEntity="Interval", mappedBy="intervalType", fetch="EXTRA_LAZY")
     */
    private $intervals;

    public function __construct()
    {
        $this->intervals = new ArrayCollection();
    }
}
class Interval
{
    /**
     * @ORM\ManyToOne(targetEntity="IntervalType", inversedBy="intervals")
     * @ORM\JoinColumn(name="interval_type_id", referencedColumnName="id", nullable=false)
     */
    private $intervalType;

    /**
     * @ORM\ManyToMany(targetEntity="Task", fetch="EAGER")
     * @ORM\JoinTable(name="interval_mapping",
     *      joinColumns={@JoinColumn(name="interval_id", referencedColumnName="id")},
     *      inverseJoinColumns={@JoinColumn(name="task_id", referencedColumnName="task_id", unique=true)}
     * )
     */
    private $tasks;

    public function __construct()
    {
        $this->tasks = new ArrayCollection();
    }
}
class IntervalGroupRepository extends EntityRepository
{
    public function findAllAscendingByName()
    {
        $qb = $this->createQueryBuilder('ig');

        $qb
            ->select(['ig', 'it', 'i'])
            ->leftJoin('ig.intervalTypes', 'it')
            ->leftJoin('it.intervals', 'i');

        $query = $qb->getQuery();

        $query
            ->setFetchMode(Interval::class, 'tasks', ClassMetadataInfo::FETCH_LAZY);

        return $query->getResult();
    }
}

Expected behavior

The fetch mode override (as set in setFetchMode()) should be respected during hydration. UnitOfWork::createEntity's $assoc['fetch'] should check the $hints array to see if it is overridden, or use the default annotation value if not.

I believe overriding a fetch annotation should be possible to do, though perhaps I'm doing it the wrong way (in which case I'm happy to be pointed in the right direction!).

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions