Явно установите Id с Doctrine при использовании стратегии «AUTO» - PullRequest
90 голосов
/ 14 марта 2011

Моя сущность использует эту аннотацию для своего идентификатора:

/**
 * @orm:Id
 * @orm:Column(type="integer")
 * @orm:GeneratedValue(strategy="AUTO")
 */
protected $id;

Из чистой базы данных я импортирую существующие записи из более старой базы данных и пытаюсь сохранить те же идентификаторы. Затем, при добавлении новых записей, я хочу, чтобы MySQL автоматически увеличивал столбец идентификатора как обычно.

К сожалению, похоже, Doctrine2 полностью игнорирует указанный идентификатор.


Новое решение

В соответствии с приведенными ниже рекомендациями предпочтительным решением является следующее:

$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, и оно работало, как и ожидалось, то есть объекты с пользовательским идентификатором хранились с этим идентификатором, в то время как объекты без указанного идентификатора использовали lastGeneratedId() + 1.

Ответы [ 7 ]

45 голосов
/ 23 августа 2012

Хотя ваше решение отлично работает с MySQL, мне не удалось заставить его работать с PostgreSQL, поскольку оно основано на последовательности.

Я должен добавить эту строку, чтобы она работала идеально:

$metadata->setIdGenerator(new \Doctrine\ORM\Id\AssignedGenerator());

С уважением,

28 голосов
/ 11 июля 2013

Возможно, что доктрина изменилась, но теперь правильный путь:

$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
7 голосов
/ 28 ноября 2013

В случае, если сущность является частью наследования таблицы классов , вам нужно изменить генератор идентификатора в метаданных класса для обеих сущностей (сущности, которую вы сохраняете, и корняюридическое лицо)

5 голосов
/ 19 августа 2016

Новое решение работает нормально только тогда, когда ВСЕ сущности имеют идентификатор перед вставкой.Когда один объект имеет идентификатор, а другой нет - новое решение не работает.

Я использую эту функцию для импорта всех своих данных:

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();
    }
}
3 голосов
/ 23 сентября 2016

Решение для 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, потому что я еще не пробовал другие СУБД.

1 голос
/ 04 июля 2018

Вдохновленный Villermen работой, я создал библиотеку tseho / doctrine-назначенный-идентификатор , которая позволяет вам вручную назначать идентификаторы сущности Doctrine, даже когда сущность использует состояния АВТО, ПОСЛЕДОВАТЕЛЬНОСТЬ, ИДЕНТИЧНОСТЬ или UUID.

Вы никогда не должны использовать его в производстве , но это действительно полезно для функциональных тестов.

Библиотека автоматически обнаружит объекты с назначенным идентификатором и заменит генератор только при необходимости. Библиотека откатится на исходный генератор, когда у экземпляра нет назначенного идентификатора.

Замена генератора происходит в Doctrine EventListener, нет необходимости добавлять какой-либо дополнительный код в ваши приборы.

1 голос
/ 26 марта 2018

Я создал библиотеку , чтобы установить будущие идентификаторы для сущностей Doctrine.Он возвращается к исходной стратегии генерации идентификаторов, когда все идентификаторы в очереди используются для минимизации воздействия.Это должно быть легкое добавление для модульных тестов, чтобы подобный код не повторялся.

...