1
0
mirror of synced 2025-02-20 14:13:15 +03:00

DDC-952 - Implemented first approach for batching eager loads of ToOne associations.

This commit is contained in:
Benjamin Eberlei 2010-12-31 10:54:20 +01:00
parent e0b835178b
commit 32df9451fd
4 changed files with 98 additions and 9 deletions

View File

@ -59,6 +59,7 @@ class ObjectHydrator extends AbstractHydrator
$this->_resultPointers =
$this->_idTemplate = array();
$this->_resultCounter = 0;
$this->_hints['deferEagerLoad'] = true;
foreach ($this->_rsm->aliasMap as $dqlAlias => $className) {
$this->_identifierMap[$dqlAlias] = array();
@ -132,6 +133,8 @@ class ObjectHydrator extends AbstractHydrator
$coll->takeSnapshot();
}
$this->_em->getUnitOfWork()->triggerEagerLoads();
return $result;
}

View File

@ -560,7 +560,10 @@ class BasicEntityPersister
$result = $stmt->fetch(PDO::FETCH_ASSOC);
$stmt->closeCursor();
return $this->_createEntity($result, $entity, $hints);
$hints['deferEagerLoad'] = true;
$entity = $this->_createEntity($result, $entity, $hints);
$this->_em->getUnitOfWork()->triggerEagerLoads();
return $entity;
}
/**
@ -577,6 +580,10 @@ class BasicEntityPersister
*/
public function loadOneToOneEntity(array $assoc, $sourceEntity, $targetEntity, array $identifier = array())
{
if ($foundEntity = $this->_em->getUnitOfWork()->tryGetById($identifier, $assoc['targetEntity'])) {
return $foundEntity;
}
$targetClass = $this->_em->getClassMetadata($assoc['targetEntity']);
if ($assoc['isOwningSide']) {
@ -739,10 +746,13 @@ class BasicEntityPersister
$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
$stmt->closeCursor();
$hints = array('deferEagerLoads' => true);
foreach ($result as $row) {
$entities[] = $this->_createEntity($row);
$entities[] = $this->_createEntity($row, null, $hints);
}
$this->_em->getUnitOfWork()->triggerEagerLoads();
return $entities;
}
@ -870,7 +880,14 @@ class BasicEntityPersister
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset);
list($params, $types) = $this->expandParameters($criteria);
return $this->_conn->executeQuery($sql, $params, $types);
$stmt = $this->_conn->executeQuery($sql, $params, $types);
$hints = array('deferEagerLoads' => true);
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$coll->hydrateAdd($this->_createEntity($result, null, $hints));
}
$stmt->closeCursor();
$this->_em->getUnitOfWork()->triggerEagerLoads();
}
/**
@ -1330,7 +1347,16 @@ class BasicEntityPersister
$sql = $this->_getSelectEntitiesSQL($criteria, $assoc, 0, $limit, $offset);
list($params, $types) = $this->expandParameters($criteria);
return $this->_conn->executeQuery($sql, $params, $types);
$stmt = $this->_conn->executeQuery($sql, $params, $types);
$hints = array('deferEagerLoads' => true);
while ($result = $stmt->fetch(PDO::FETCH_ASSOC)) {
$coll->hydrateAdd($this->_createEntity($result, null, $hints));
}
$stmt->closeCursor();
$this->_em->getUnitOfWork()->triggerEagerLoads();
return $stmt;
}
/**

View File

@ -1928,10 +1928,18 @@ class UnitOfWork implements PropertyChangedListener
$newValue = $this->getEntityPersister($assoc['targetEntity'])
->loadOneToOneEntity($assoc, $entity, null, $associatedId);
} else {
if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER) {
// TODO: Maybe it could be optimized to do an eager fetch with a JOIN inside
// the persister instead of this rather unperformant approach.
$newValue = $this->em->find($assoc['targetEntity'], $associatedId);
if ($assoc['fetch'] == ClassMetadata::FETCH_EAGER && isset($hints['deferEagerLoad'])) {
if (!isset($this->eagerLoadingEntities[$assoc['targetEntity']])) {
$this->eagerLoadingEntities[$assoc['targetEntity']] = array();
}
// TODO: Is there a faster approach?
$this->eagerLoadingEntities[$assoc['targetEntity']] = array_merge_recursive(
$this->eagerLoadingEntities[$assoc['targetEntity']],
array_map(function($id) {
return array($id);
}, $associatedId)
);
} else {
$newValue = $this->em->getProxyFactory()->getProxy($assoc['targetEntity'], $associatedId);
}
@ -1983,6 +1991,26 @@ class UnitOfWork implements PropertyChangedListener
}
/**
<<<<<<< HEAD
=======
* @return void
*/
public function triggerEagerLoads()
{
if (!$this->eagerLoadingEntities) {
return;
}
$eagerLoadingEntities = $this->eagerLoadingEntities;
$this->eagerLoadingEntities = array();
foreach ($eagerLoadingEntities AS $entityName => $ids) {
$this->getEntityPersister($entityName)->loadAll($ids);
}
}
/**
>>>>>>> DDC-952 - Implemented first approach for batching eager loads of ToOne associations.
* Initializes (loads) an uninitialized persistent collection of an entity.
*
* @param PeristentCollection $collection The collection to initialize.

View File

@ -21,6 +21,10 @@ class DDC633Test extends \Doctrine\Tests\OrmFunctionalTestCase
}
}
/**
* @group DDC-633
* @group DDC-952
*/
public function testOneToOneEager()
{
$app = new DDC633Appointment();
@ -35,7 +39,35 @@ class DDC633Test extends \Doctrine\Tests\OrmFunctionalTestCase
$eagerAppointment = $this->_em->find(__NAMESPACE__ . '\DDC633Appointment', $app->id);
$this->assertNotType('Doctrine\ORM\Proxy\Proxy', $eagerAppointment->patient);
// Eager loading still produces proxies
$this->assertType('Doctrine\ORM\Proxy\Proxy', $eagerAppointment->patient);
$this->assertTrue($eagerAppointment->patient->__isInitialized__, "Proxy should already be initialized due to eager loading!");
}
/**
* @group DDC-633
* @group DDC-952
*/
public function testDQLDeferredEagerLoad()
{
for ($i = 0; $i < 10; $i++) {
$app = new DDC633Appointment();
$pat = new DDC633Patient();
$app->patient = $pat;
$pat->appointment = $app;
$this->_em->persist($app);
$this->_em->persist($pat);
}
$this->_em->flush();
$this->_em->clear();
$appointments = $this->_em->createQuery("SELECT a FROM " . __NAMESPACE__ . "\DDC633Appointment a")->getResult();
foreach ($appointments AS $eagerAppointment) {
$this->assertType('Doctrine\ORM\Proxy\Proxy', $eagerAppointment->patient);
$this->assertTrue($eagerAppointment->patient->__isInitialized__, "Proxy should already be initialized due to eager loading!");
}
}
}