1
0
mirror of synced 2025-01-18 22:41:43 +03:00

[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:
Benjamin Eberlei 2011-03-16 22:51:32 +01:00
parent 4b98e3ea8e
commit 5192306d39
5 changed files with 85 additions and 8 deletions

View File

@ -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.
*

View File

@ -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))));
}
}

View File

@ -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());
}
}

View File

@ -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));

View File

@ -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());
}
}