[DDC-952] One last commit with some refactorings, additional comments and two new tests. Also added convenience method Query::setFetchMode($className, $assocName)
This commit is contained in:
parent
4b98e3ea8e
commit
5192306d39
@ -336,6 +336,26 @@ abstract class AbstractQuery
|
||||
return $this->_expireResultCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the default fetch mode of an association for this query.
|
||||
*
|
||||
* $fetchMode can be one of ClassMetadata::FETCH_EAGER or ClassMetadata::FETCH_LAZY
|
||||
*
|
||||
* @param string $class
|
||||
* @param string $assocName
|
||||
* @param int $fetchMode
|
||||
* @return AbstractQuery
|
||||
*/
|
||||
public function setFetchMode($class, $assocName, $fetchMode)
|
||||
{
|
||||
if ($fetchMode !== Mapping\ClassMetadata::FETCH_EAGER) {
|
||||
$fetchMode = Mapping\ClassMetadata::FETCH_LAZY;
|
||||
}
|
||||
|
||||
$this->_hints['fetchMode'][$class][$assocName] = $fetchMode;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines the processing mode to be used during hydration / result set transformation.
|
||||
*
|
||||
|
@ -1895,7 +1895,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
}
|
||||
|
||||
// Loading the entity right here, if its in the eager loading map get rid of it there.
|
||||
unset($this->eagerLoadingEntities[$class->name][$idHash]);
|
||||
unset($this->eagerLoadingEntities[$class->rootEntityName][$idHash]);
|
||||
|
||||
// Properly initialize any unfetched associations, if partial objects are not allowed.
|
||||
if ( ! isset($hints[Query::HINT_FORCE_PARTIAL_LOAD])) {
|
||||
@ -1926,6 +1926,10 @@ class UnitOfWork implements PropertyChangedListener
|
||||
$class->reflFields[$field]->setValue($entity, null);
|
||||
$this->originalEntityData[$oid][$field] = null;
|
||||
} else {
|
||||
if (!isset($hints['fetchMode'][$class->name][$field])) {
|
||||
$hints['fetchMode'][$class->name][$field] = $assoc['fetch'];
|
||||
}
|
||||
|
||||
// Foreign key is set
|
||||
// Check identity map first
|
||||
// FIXME: Can break easily with composite keys if join column values are in
|
||||
@ -1937,25 +1941,28 @@ class UnitOfWork implements PropertyChangedListener
|
||||
// if this is an uninitialized proxy, we are deferring eager loads,
|
||||
// this association is marked as eager fetch, and its an uninitialized proxy (wtf!)
|
||||
// then we cann append this entity for eager loading!
|
||||
if (isset($hints['fetchEager'][$class->name][$field]) &&
|
||||
if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER &&
|
||||
isset($hints['deferEagerLoad']) &&
|
||||
!$targetClass->isIdentifierComposite &&
|
||||
$newValue instanceof Proxy &&
|
||||
$newValue->__isInitialized__ === false) {
|
||||
|
||||
$this->eagerLoadingEntities[$assoc['targetEntity']][$relatedIdHash] = current($associatedId);
|
||||
$this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
|
||||
}
|
||||
} else {
|
||||
if ($targetClass->subClasses) {
|
||||
// If it might be a subtype, it can not be lazy
|
||||
// If it might be a subtype, it can not be lazy. There isn't even
|
||||
// a way to solve this with deferred eager loading, which means putting
|
||||
// an entity with subclasses at a *-to-one location is really bad! (performance-wise)
|
||||
$newValue = $this->getEntityPersister($assoc['targetEntity'])
|
||||
->loadOneToOneEntity($assoc, $entity, null, $associatedId);
|
||||
} else {
|
||||
// Deferred eager load only works for single identifier classes
|
||||
if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER || isset($hints['fetchEager'][$class->name][$field])) {
|
||||
|
||||
if ($hints['fetchMode'][$class->name][$field] == ClassMetadata::FETCH_EAGER) {
|
||||
if (isset($hints['deferEagerLoad']) && !$targetClass->isIdentifierComposite) {
|
||||
// TODO: Is there a faster approach?
|
||||
$this->eagerLoadingEntities[$assoc['targetEntity']][$relatedIdHash] = current($associatedId);
|
||||
$this->eagerLoadingEntities[$targetClass->rootEntityName][$relatedIdHash] = current($associatedId);
|
||||
|
||||
$newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
|
||||
} else {
|
||||
@ -2032,7 +2039,7 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
foreach ($eagerLoadingEntities AS $entityName => $ids) {
|
||||
$class = $this->em->getClassMetadata($entityName);
|
||||
$this->getEntityPersister($entityName)->loadAll(array_combine($class->identifier, array($ids)));
|
||||
$this->getEntityPersister($entityName)->loadAll(array_combine($class->identifier, array(array_values($ids))));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -946,4 +946,35 @@ class BasicFunctionalTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
|
||||
$this->assertNull($this->_em->find(get_class($ph), $ph->phonenumber)->getUser());
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-952
|
||||
*/
|
||||
public function testManyToOneFetchModeQuery()
|
||||
{
|
||||
$user = new CmsUser();
|
||||
$user->username = "beberlei";
|
||||
$user->name = "Benjamin E.";
|
||||
$user->status = 'active';
|
||||
|
||||
$article = new CmsArticle();
|
||||
$article->topic = "foo";
|
||||
$article->text = "bar";
|
||||
$article->user = $user;
|
||||
|
||||
$this->_em->persist($article);
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$qc = $this->getCurrentQueryCount();
|
||||
$dql = "SELECT a FROM Doctrine\Tests\Models\CMS\CmsArticle a WHERE a.id = ?1";
|
||||
$article = $this->_em->createQuery($dql)
|
||||
->setParameter(1, $article->id)
|
||||
->setFetchMode('Doctrine\Tests\Models\CMS\CmsArticle', 'user', \Doctrine\ORM\Mapping\ClassMetadata::FETCH_EAGER)
|
||||
->getSingleResult();
|
||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $article->user, "It IS a proxy, ...");
|
||||
$this->assertTrue($article->user->__isInitialized__, "...but its initialized!");
|
||||
$this->assertEquals($qc+2, $this->getCurrentQueryCount());
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\Tests\Models\CMS\CmsUser,
|
||||
Doctrine\Tests\Models\CMS\CmsArticle;
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
@ -335,7 +336,7 @@ class QueryTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$this->_em->clear();
|
||||
|
||||
$articles = $this->_em->createQuery('select a from Doctrine\Tests\Models\CMS\CmsArticle a')
|
||||
->setHint('fetchEager', array('Doctrine\Tests\Models\CMS\CmsArticle' => array('user' => true)))
|
||||
->setFetchMode('Doctrine\Tests\Models\CMS\CmsArticle', 'user', ClassMetadata::FETCH_EAGER)
|
||||
->getResult();
|
||||
|
||||
$this->assertEquals(10, count($articles));
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
|
||||
use Doctrine\ORM\Mapping\ClassMetadata;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
@ -349,4 +351,20 @@ class SingleTableInheritanceTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$ref = $this->_em->getReference('Doctrine\Tests\Models\Company\CompanyFixContract', $this->fix->getId());
|
||||
$this->assertInstanceOf('Doctrine\ORM\Proxy\Proxy', $ref, "A proxy can be generated only if no subclasses exists for the requested reference.");
|
||||
}
|
||||
|
||||
/**
|
||||
* @group DDC-952
|
||||
*/
|
||||
public function testEagerLoadInheritanceHierachy()
|
||||
{
|
||||
$this->loadFullFixture();
|
||||
|
||||
$dql = 'SELECT f FROM Doctrine\Tests\Models\Company\CompanyFixContract f WHERE f.id = ?1';
|
||||
$contract = $this->_em->createQuery($dql)
|
||||
->setFetchMode('Doctrine\Tests\Models\Company\CompanyFixContract', 'salesPerson', ClassMetadata::FETCH_EAGER)
|
||||
->setParameter(1, $this->fix->getId())
|
||||
->getSingleResult();
|
||||
|
||||
$this->assertNotInstanceOf('Doctrine\ORM\Proxy\Proxy', $contract->getSalesPerson());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user