Явно задаю Id с помощью Doctrine при использовании стратегии "AUTO"
Мой объект использует эту аннотацию для этого ID:
/**
* @orm:Id
* @orm:Column(type="integer")
* @orm:GeneratedValue(strategy="AUTO")
*/
protected $id;
Из чистой базы данных я импортирую в существующие записи из старой базы данных и пытаюсь сохранить те же идентификаторы. Затем, добавляя новые записи, я хочу, чтобы MySQL автоматически увеличивал индексный столбец как обычно.
К сожалению, похоже, Doctrine2 полностью игнорирует указанный ID.
Новое решение
В соответствии с рекомендациями ниже предпочтительным является следующее решение:
$this->em->persist($entity);
$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
Старое решение
Поскольку Doctrine отбрасывает ClassMetaData для определения стратегии генератора, она должна быть изменена после управления объектом в EntityManager:
$this->em->persist($entity);
$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$this->em->flush();
Я только что протестировал это в MySQL и работал как ожидалось, то есть объекты с пользовательским идентификатором были сохранены с этим ID, в то время как те, у кого нет идентификатора, использовали lastGeneratedId() + 1
.
Ответы
Ответ 1
Хотя ваше решение отлично работает с MySQL, мне не удалось заставить его работать с PostgreSQL по мере его последовательности.
Я должен добавить эту строку, чтобы она работала отлично:
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
С уважением,
Ответ 2
Возможно, что доктрина изменилась, но теперь правильный путь:
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
Ответ 3
Если объект является частью наследования таблицы классов , вам нужно изменить идентификатор-идентификатор в метаданных класса для объектов (объект, который вы сохраняете, и корневой объект)
Ответ 4
Новое решение отлично работает, только когда все объекты имеют id перед вставкой. Когда у одного объекта есть идентификатор, а другой нет - новое решение не работает.
Я использую эту функцию для импорта всех моих данных:
function createEntity(\Doctrine\ORM\EntityManager $em, $entity, $id = null)
{
$className = get_class($entity);
if ($id) {
$idRef = new \ReflectionProperty($className, "id");
$idRef->setAccessible(true);
$idRef->setValue($entity, $id);
$metadata = $em->getClassMetadata($className);
/** @var \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata */
$generator = $metadata->idGenerator;
$generatorType = $metadata->generatorType;
$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());
$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
$unitOfWork = $em->getUnitOfWork();
$persistersRef = new \ReflectionProperty($unitOfWork, "persisters");
$persistersRef->setAccessible(true);
$persisters = $persistersRef->getValue($unitOfWork);
unset($persisters[$className]);
$persistersRef->setValue($unitOfWork, $persisters);
$em->persist($entity);
$em->flush();
$idRef->setAccessible(false);
$metadata->setIdGenerator($generator);
$metadata->setIdGeneratorType($generatorType);
$persisters = $persistersRef->getValue($unitOfWork);
unset($persisters[$className]);
$persistersRef->setValue($unitOfWork, $persisters);
$persistersRef->setAccessible(false);
} else {
$em->persist($entity);
$em->flush();
}
}
Ответ 5
Решение для Doctrine 2.5 и MySQL
"Новое решение" не работает с Doctrine 2.5 и MySQL. Вы должны использовать:
$metadata = $this->getEntityManager()->getClassMetaData(Entity::class);
$metadata->setIdGenerator(new AssignedGenerator());
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE);
Однако я могу только подтвердить это для MySQL, потому что я еще не пробовал никаких других СУБД.
Ответ 6
Я создал библиотеку для установки будущих идентификаторов для сущностей Doctrine. Он возвращается к исходной стратегии генерации идентификаторов, когда все идентификаторы в очереди используются для минимизации воздействия. Это должно быть легкое добавление для модульных тестов, чтобы подобный код не повторялся.
Ответ 7
Вдохновленный работой Виллермена, я создал библиотеку tseho/doctrine-назначенный идентификатор, которая позволяет вручную назначать идентификаторы сущности Doctrine, даже когда сущность использует операторы состояний AUTO, SEQUENCE, IDENTITY или UUID.
Вы никогда не должны использовать это в производстве, но это действительно полезно для функциональных тестов.
Библиотека автоматически обнаружит объекты с назначенным идентификатором и заменит генератор только при необходимости. Библиотека откатится на исходный генератор, когда экземпляр не имеет назначенного идентификатора.
Замена генератора происходит в Doctrine EventListener, нет необходимости добавлять дополнительный код в ваши приборы.