private function loadReferenceManyCollectionOwningSide(PersistentCollectionInterface $collection)
    {
        $mapping = $collection->getMapping();

        /** @var Identifier[] $identifiers */
        $identifiers = array_map(
            function ($referenceData) use ($mapping) {
                return $this->ap->loadReference($mapping, $referenceData);
            },
            $collection->getRawData()
        );

        //reverse + limit must be applied here rather than on the query,
        //since we are potentially performing multiple queries
        if ($mapping->reverse) {
            $identifiers = array_reverse($identifiers);
        }
        if ($mapping->limit !== null) {
            $identifiers = array_slice($identifiers, 0, $mapping->limit);
        }

        //build document proxies and group by class
        $groupedIds = [];
        foreach ($identifiers as $key => $identifier) {
            //create a reference to the class+id and add it to the collection
            $reference = $identifier->getDocument($this->dm);

            if ($mapping->type === Type::MAP) {
                $collection->set($key, $reference);
            } else {
                $collection->add($reference);
            }

            //only query for the referenced object if it is not already initialized
            if ($reference instanceof Proxy && !$reference->__isInitialized__) {
                $className                = $identifier->class->name;
                $groupedIds[$className][] = $identifier;
            }
        }

        //load documents
        foreach ($groupedIds as $className => $batch) {
            $class   = $this->dm->getClassMetadata($className);
            $filters = array_merge(
                [(array)$mapping->criteria],
                $this->dm->getFilterCollection()->getFilterCriteria($class)
            );

            $qb = $this->dm->createQueryBuilder($className);

            if (!empty($filters)) {
                //filters require a full table scan
                //TODO: needs documentation

                //add identifiers to the query as OR conditions
                /** @var Identifier $identifier */
                foreach ($batch as $identifier) {
                    $expr = $qb->expr();
                    $identifier->addToQueryCondition($expr);
                    $qb->addOr($expr);
                }

                //add any other filter criteria
                foreach ($filters as $filter) {
                    $qb->addCriteria($filter);
                }

                $query = $qb->getQuery();
            } else {
                //load using batchgetitem
                foreach ($batch as $identifier) {
                    $qb->get()->setIdentifier($identifier)->batch();
                }

                $query = $qb->getBatch();
            }

            foreach ($query->getMarshalledResult() as $documentData) {
                $identifier = $class->createIdentifier($documentData);
                $document   = $this->uow->getByIdentifier($identifier);

                if ($document instanceof Proxy && !$document->__isInitialized()) {
                    $data = $this->hydratorFactory->hydrate($document, $documentData);
                    $this->uow->setOriginalDocumentData($document, $data);
                    $document->__isInitialized__ = true;
                }
            }
        }
    }