1.Создаем класс My\EntityManager
use Doctrine\Common\EventManager;
use Doctrine\DBAL\Connection;
use Doctrine\ORM\Configuration;
use Doctrine\ORM\ORMException;
use Doctrine\ORM\Query;
class EntityManager extends \Doctrine\ORM\EntityManager
{
/**
* @param array|Connection $connection
* @param Configuration $config
* @param EventManager|null $eventManager
*
* @return EntityManager
*
* @throws ORMException
*/
public static function create($connection, Configuration $config, EventManager $eventManager = null)
{
if (!$config->getMetadataDriverImpl()) {
throw ORMException::missingMappingDriverImpl();
}
$connection = static::createConnection($connection, $config, $eventManager);
// порождаем самого себя
return new EntityManager($connection, $config, $connection->getEventManager());
}
/**
* Например принудительный HINT_REFRESH:
*
* @param string $dql
*
* @return Query|mixed
*/
public function createQuery($dql = '')
{
// устанавливаем принудительное обновление запрашиваемых объектов
$query = parent::createQuery($dql);
$query->setHint(Query::HINT_REFRESH, true);
return $query;
}
/**
* {@inheritDoc}
*/
public function close(): void
{
// ничего не делаем
// Если база данных возвращает ошибку выполнения SQL, то Doctrine выбрасывает исключение и
// закрывает EntityManager + закрывает подключение к базе данных.
// Это поведение мы считаем неверным, поэтому переопределяем его.
}
}2. Подменяем
простой вариант:
parameters:
doctrine.orm.entity_manager.class: My\EntityManagerсложный вариант:
doctrine.orm.entity_manager_db_entity_manager:
class: My\EntityManager
factory: ['My\EntityManager', 'create']
arguments: ['@doctrine.dbal.connection_db_connection', '@doctrine.orm.entity_manager_db_configuration',]
public: true
lazy: true
autowire: false
autoconfigure: false
tags:
- {name: 'container.preload', class: 'Doctrine\ORM\Proxy\Autoloader', priority: 100}Готово.
Внимание, даже если мы используем Query::HINT_REFRESH, то это не влияет на то, как доктрина смотрит на строки - если доктрина вытащила из таблицы строку с данными и ассоциировала ее с определенным php-классом, то далее она уже не меняет эту ассоциацию (хранится эта ассоциация в UnitOfWork->identityMap).
Когда это важно? А вот когда используется DiscriminatorMap, при этом мы пишем запросы используя createNativeQuery, имею ввиду что-то вроде этого:
$this->rsm = new ResultSetMappingBuilder($this->getEntityManager());
$this->rsm->addRootEntityFromClassMetadata(Document::class, 't');
$sql = '
SELECT
*
FROM document
WHERE available = 1';
$this->getEntityManager()->createNativeQuery($sql, $this->rsm)->getResult();Фактически, такой запрос вернет объекты класса Document которые конечно являются частичными от полной версии объектов, например таких, которые используя DiscriminatorMap являются расширениями таблицы document. Получается, что если Вы используете такую магию у Вас есть 2 выхода:
createNativeQuery после того, как Вы вытянули все данные обычными запросамиcreateNativeQuery вызывать $entityManager->clear(); который сбросит UnitOfWork (в том числе identityMap)createNativeQuery и гидрировать объекты каким-то другим способомЯ для себя пока что выбирают такую стратегию:
createNativeQuery запросы$entityManager->clear(); ведь объекты созданные createNativeQuery не являются полноценнымиУдачки.
Комментарии
Комментариев пока нет.