handle update/delete queries
This commit is contained in:
parent
61bff7d5f6
commit
d135e402bb
@ -829,13 +829,13 @@ However, you can use the cache API to check / invalidate cache entries.
|
||||
/* var $cache \Doctrine\ORM\Cache */
|
||||
$cache = $em->getCache();
|
||||
|
||||
$cache->containsEntity('State', 1) // Check if the cache exists
|
||||
$cache->evictEntity('State', 1); // Remove an entity from cache
|
||||
$cache->evictEntityRegion('State'); // Remove all entities from cache
|
||||
$cache->containsEntity('Entity\State', 1) // Check if the cache exists
|
||||
$cache->evictEntity('Entity\State', 1); // Remove an entity from cache
|
||||
$cache->evictEntityRegion('Entity\State'); // Remove all entities from cache
|
||||
|
||||
$cache->containsCollection('State', 'cities', 1); // Check if the cache exists
|
||||
$cache->evictCollection('State', 'cities', 1); // Remove an entity collection from cache
|
||||
$cache->evictCollectionRegion('State', 'cities'); // Remove all collections from cache
|
||||
$cache->containsCollection('Entity\State', 'cities', 1); // Check if the cache exists
|
||||
$cache->evictCollection('Entity\State', 'cities', 1); // Remove an entity collection from cache
|
||||
$cache->evictCollectionRegion('Entity\State', 'cities'); // Remove all collections from cache
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
@ -843,10 +843,8 @@ Limitations
|
||||
Composite primary key
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
.. note::
|
||||
|
||||
Composite primary key are supported by second level cache, however when one of the keys is an association
|
||||
the cached entity should always be retrieved using the association identifier.
|
||||
Composite primary key are supported by second level cache, however when one of the keys is an association
|
||||
the cached entity should always be retrieved using the association identifier.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
@ -895,4 +893,47 @@ A ``Doctrine\\ORM\\Cache\\ConcurrentRegion`` is designed to store concurrently m
|
||||
By default, Doctrine provides a very simple implementation based on file locks ``Doctrine\\ORM\\Cache\\Region\\FileLockRegion``.
|
||||
|
||||
If you want to use an ``READ_WRITE`` cache, you should consider providing your own cache region.
|
||||
for more details about how to implement a cache region please see :ref:`reference-second-level-cache-regions`
|
||||
for more details about how to implement a cache region please see :ref:`reference-second-level-cache-regions`
|
||||
|
||||
|
||||
DELETE / UPDATE queries
|
||||
~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
DQL UPDATE / DELETE statements are ported directly into a database and bypass the second-level cache,
|
||||
Entities that are already cached will NOT be invalidated.
|
||||
However the cached data could be evicted using the cache API or an special query hint.
|
||||
|
||||
|
||||
Execute the ``UPDATE`` and invalidate ``all cache entries`` using ``Query::HINT_CACHE_EVICT``
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Execute and invalidate
|
||||
$this->_em->createQuery("UPDATE Entity\Country u SET u.name = 'unknown' WHERE u.id = 1")
|
||||
->setHint(Query::HINT_CACHE_EVICT, true)
|
||||
->execute();
|
||||
|
||||
|
||||
Execute the ``UPDATE`` and invalidate ``all cache entries`` using the cache API
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Execute
|
||||
$this->_em->createQuery("UPDATE Entity\Country u SET u.name = 'unknown' WHERE u.id = 1")
|
||||
->execute();
|
||||
// Invoke Cache API
|
||||
$em->getCache()->evictEntityRegion('Entity\Country');
|
||||
|
||||
|
||||
Execute the ``UPDATE`` and invalidate ``a specific cache entry`` using the cache API
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
// Execute
|
||||
$this->_em->createQuery("UPDATE Entity\Country u SET u.name = 'unknown' WHERE u.id = 1")
|
||||
->execute();
|
||||
// Invoke Cache API
|
||||
$em->getCache()->evictEntity('Entity\Country', 1);
|
@ -129,6 +129,11 @@ abstract class AbstractQuery
|
||||
*/
|
||||
protected $cacheable = false;
|
||||
|
||||
/**
|
||||
* @var boolean
|
||||
*/
|
||||
protected $hasCache = false;
|
||||
|
||||
/**
|
||||
* Second level cache region name.
|
||||
*
|
||||
@ -162,9 +167,10 @@ abstract class AbstractQuery
|
||||
{
|
||||
$this->_em = $em;
|
||||
$this->parameters = new ArrayCollection();
|
||||
$this->hasCache = $this->_em->getConfiguration()->isSecondLevelCacheEnabled();
|
||||
|
||||
if ($this->_em->getConfiguration()->isSecondLevelCacheEnabled()) {
|
||||
$this->cacheLogger = $em->getConfiguration()
|
||||
if ($this->hasCache) {
|
||||
$this->cacheLogger = $em->getConfiguration()
|
||||
->getSecondLevelCacheConfiguration()
|
||||
->getCacheLogger();
|
||||
}
|
||||
@ -220,7 +226,7 @@ abstract class AbstractQuery
|
||||
*/
|
||||
protected function isCacheEnabled()
|
||||
{
|
||||
return $this->cacheable && $this->_em->getConfiguration()->isSecondLevelCacheEnabled();
|
||||
return $this->cacheable && $this->hasCache;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -64,6 +64,11 @@ final class Query extends AbstractQuery
|
||||
*/
|
||||
const HINT_CACHE_ENABLED = 'doctrine.cache.enabled';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const HINT_CACHE_EVICT = 'doctrine.cache.evict';
|
||||
|
||||
/**
|
||||
* Internal hint: is set to the proxy entity that is currently triggered for loading
|
||||
*
|
||||
@ -287,11 +292,34 @@ final class Query extends AbstractQuery
|
||||
throw QueryException::invalidParameterNumber();
|
||||
}
|
||||
|
||||
// evict all cache for the entity region
|
||||
if ($this->hasCache && isset($this->_hints[self::HINT_CACHE_EVICT]) && $this->_hints[self::HINT_CACHE_EVICT]) {
|
||||
$this->evictEntityCacheRegion();
|
||||
}
|
||||
|
||||
list($sqlParams, $types) = $this->processParameterMappings($paramMappings);
|
||||
|
||||
return $executor->execute($this->_em->getConnection(), $sqlParams, $types);
|
||||
}
|
||||
|
||||
/**
|
||||
* Evict entity cache region
|
||||
*/
|
||||
private function evictEntityCacheRegion()
|
||||
{
|
||||
$AST = $this->getAST();
|
||||
|
||||
if ($AST instanceof \Doctrine\ORM\Query\AST\SelectStatement) {
|
||||
throw new QueryException('The hint "HINT_CACHE_EVICT" is not valid for select statements.');
|
||||
}
|
||||
|
||||
$className = ($AST instanceof \Doctrine\ORM\Query\AST\DeleteStatement)
|
||||
? $AST->deleteClause->abstractSchemaName
|
||||
: $AST->updateClause->abstractSchemaName;
|
||||
|
||||
$this->_em->getCache()->evictEntityRegion($className);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes query parameter mappings.
|
||||
*
|
||||
|
@ -827,6 +827,38 @@ class SecondLevelCacheQueryCacheTest extends SecondLevelCacheAbstractTest
|
||||
$this->assertEquals(1, $this->secondLevelCacheLogger->getRegionMissCount('bar_region'));
|
||||
}
|
||||
|
||||
public function testHintClearEntityRegionUpdateStatement()
|
||||
{
|
||||
$this->evictRegions();
|
||||
$this->loadFixturesCountries();
|
||||
|
||||
$this->assertTrue($this->cache->containsEntity('Doctrine\Tests\Models\Cache\Country', $this->countries[0]->getId()));
|
||||
$this->assertTrue($this->cache->containsEntity('Doctrine\Tests\Models\Cache\Country', $this->countries[1]->getId()));
|
||||
|
||||
$this->_em->createQuery('DELETE Doctrine\Tests\Models\Cache\Country u WHERE u.id = 4')
|
||||
->setHint(Query::HINT_CACHE_EVICT, true)
|
||||
->execute();
|
||||
|
||||
$this->assertFalse($this->cache->containsEntity('Doctrine\Tests\Models\Cache\Country', $this->countries[0]->getId()));
|
||||
$this->assertFalse($this->cache->containsEntity('Doctrine\Tests\Models\Cache\Country', $this->countries[1]->getId()));
|
||||
}
|
||||
|
||||
public function testHintClearEntityRegionDeleteStatement()
|
||||
{
|
||||
$this->evictRegions();
|
||||
$this->loadFixturesCountries();
|
||||
|
||||
$this->assertTrue($this->cache->containsEntity('Doctrine\Tests\Models\Cache\Country', $this->countries[0]->getId()));
|
||||
$this->assertTrue($this->cache->containsEntity('Doctrine\Tests\Models\Cache\Country', $this->countries[1]->getId()));
|
||||
|
||||
$this->_em->createQuery("UPDATE Doctrine\Tests\Models\Cache\Country u SET u.name = 'foo' WHERE u.id = 1")
|
||||
->setHint(Query::HINT_CACHE_EVICT, true)
|
||||
->execute();
|
||||
|
||||
$this->assertFalse($this->cache->containsEntity('Doctrine\Tests\Models\Cache\Country', $this->countries[0]->getId()));
|
||||
$this->assertFalse($this->cache->containsEntity('Doctrine\Tests\Models\Cache\Country', $this->countries[1]->getId()));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \Doctrine\ORM\Cache\CacheException
|
||||
* @expectedExceptionMessage Second level cache does not support partial entities.
|
||||
@ -848,7 +880,7 @@ class SecondLevelCacheQueryCacheTest extends SecondLevelCacheAbstractTest
|
||||
*/
|
||||
public function testNonCacheableQueryDeleteStatementException()
|
||||
{
|
||||
$this->_em->createQuery('DELETE Doctrine\Tests\Models\Cache\Country u WHERE u.id = 4')
|
||||
$this->_em->createQuery("DELETE Doctrine\Tests\Models\Cache\Country u WHERE u.id = 4")
|
||||
->setCacheable(true)
|
||||
->getResult();
|
||||
}
|
||||
@ -859,7 +891,7 @@ class SecondLevelCacheQueryCacheTest extends SecondLevelCacheAbstractTest
|
||||
*/
|
||||
public function testNonCacheableQueryUpdateStatementException()
|
||||
{
|
||||
$this->_em->createQuery('UPDATE Doctrine\Tests\Models\Cache\Country u SET u.name = NULL WHERE u.id = 4')
|
||||
$this->_em->createQuery("UPDATE Doctrine\Tests\Models\Cache\Country u SET u.name = 'foo' WHERE u.id = 4")
|
||||
->setCacheable(true)
|
||||
->getResult();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user