doctrine/orm · error · BadMethodCallException

Filtering a collection by Criteria is not supported by this

Error message

Filtering a collection by Criteria is not supported by this CollectionPersister.

What it means

PersistentCollection::matching($criteria) on a non-initialized collection delegates to the collection persister's loadCriteria(). ManyToManyPersister implements it (filtering over the join table), but OneToManyPersister::loadCriteria() is a stub that always throws BadMethodCallException — filtering an EXTRA_LAZY one-to-many collection by Criteria is simply not implemented.

Source

Thrown at src/Persisters/Collection/OneToManyPersister.php:151

        }

        $mapping   = $this->getMapping($collection);
        $persister = $this->uow->getEntityPersister($mapping->targetEntity);

        // only works with single id identifier entities. Will throw an
        // exception in Entity Persisters if that is not the case for the
        // 'mappedBy' field.
        $criteria = Criteria::create(true)->where(Criteria::expr()->eq($mapping->mappedBy, $collection->getOwner()));

        return $persister->exists($element, $criteria);
    }

    /**
     * {@inheritDoc}
     */
    public function loadCriteria(PersistentCollection $collection, Criteria $criteria): array
    {
        throw new BadMethodCallException('Filtering a collection by Criteria is not supported by this CollectionPersister.');
    }

    /**
     * @throws DBALException
     * @throws EntityNotFoundException
     * @throws MappingException
     */
    private function deleteEntityCollection(PersistentCollection $collection): int
    {
        $mapping     = $this->getMapping($collection);
        $identifier  = $this->uow->getEntityIdentifier($collection->getOwner());
        $sourceClass = $this->em->getClassMetadata($mapping->sourceEntity);
        $targetClass = $this->em->getClassMetadata($mapping->targetEntity);
        $columns     = [];
        $parameters  = [];
        $types       = [];

        foreach ($this->em->getMetadataFactory()->getOwningSide($mapping)->joinColumns as $joinColumn) {

View on GitHub (pinned to d9b9ff7301)

Solutions

  1. Remove FetchMode::EXTRA_LAZY from that one-to-many association so matching() initializes and filters in memory
  2. Initialize explicitly before matching: $collection->initialize(); $collection->matching($criteria)
  3. Replace matching() with a repository query: $repo->createQueryBuilder('c')->where('c.parent = :p')...

Example fix

// before
#[OneToMany(targetEntity: Task::class, mappedBy: 'project'), Fetch(FetchMode::EXTRA_LAZY)]
private Collection $tasks;
$open = $project->getTasks()->matching(Criteria::create()->where(Criteria::expr()->eq('done', false))); // throws

// after
$project->getTasks()->initialize();
$open = $project->getTasks()->matching(Criteria::create()->where(Criteria::expr()->eq('done', false)));
Defensive patterns

Strategy: fallback

Validate before calling

$collection = $project->getTasks();
if (! $collection->isInitialized()) {
    $collection->initialize(); // in-memory matching() works from here
}
$open = $collection->matching($criteria);

Try / catch

try { $result = $collection->matching($criteria); } catch (BadMethodCallException) { $collection->initialize(); $result = $collection->matching($criteria); }

Prevention

When it happens

Trigger: $entity->getChildren()->matching(Criteria::create()->where(...)) where getChildren() is an uninitialized one-to-many collection with fetch: EXTRA_LAZY. With default LAZY fetch, matching() initializes and filters in memory, so only EXTRA_LAZY hits the persister.

Common situations: Enabling EXTRA_LAZY on large child collections and then reusing existing matching() calls from when the collection was lazy; generic collection-filtering code that works on many-to-many but runs against one-to-many.

Related errors


AI-assisted analysis of doctrine/orm@d9b9ff7301 (2026-08-21). Data as JSON: /api/errors/6e925a6353bface7. Report an issue: GitHub.