Programing

"AUTO"전략을 사용할 때 Doctrine을 사용하여 명시 적으로 Id 설정

crosscheck 2020. 8. 31. 07:16
반응형

"AUTO"전략을 사용할 때 Doctrine을 사용하여 명시 적으로 Id 설정


내 엔터티는 ID에이 주석을 사용합니다.

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

깨끗한 데이터베이스에서 이전 데이터베이스의 기존 레코드를 가져와 동일한 ID를 유지하려고합니다. 그런 다음 새 레코드를 추가 할 때 MySQL이 평소와 같이 ID 열을 자동으로 늘리기를 원합니다.

불행히도 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가있는 엔터티는 해당 ID로 저장되고 지정된 ID가없는 엔터티는 lastGeneratedId() + 1.


귀하의 솔루션은 MySQL에서 잘 작동하지만 시퀀스 기반이므로 PostgreSQL에서 작동하도록 만들지 못했습니다.

완벽하게 작동하도록이 줄을 추가해야합니다.

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

친애하는,


아마도 교리가 바뀌었지만 이제 올바른 방법은 다음과 같습니다.

$metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);

엔터티가 클래스 테이블 상속의 일부인 경우 엔터티 (지속중인 엔터티 및 루트 엔터티) 에 대한 클래스 메타 데이터에서 id-generator를 변경해야합니다.


새 솔루션은 모든 엔티티가 삽입 전에 ID가있는 경우에만 제대로 작동합니다. 한 엔터티에 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();
    }
}

Doctrine 2.5 및 MySQL 용 솔루션

"새로운 솔루션"은 Doctrine 2.5 및 MySQL에서 작동하지 않습니다. 다음을 사용해야합니다.

$metadata = $this->getEntityManager()->getClassMetaData(Entity::class);
$metadata->setIdGenerator(new AssignedGenerator());
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_‌​NONE);

However I can only confirm that for MySQL,because I haven't tried any other DBMS yet.


I have created a library to set future IDs for Doctrine entities. It reverts to the original ID generation strategy when all queued IDs are consumed to minimize impact. It should be an easy drop-in for unit tests so that code like this doesn't have to be repeated.


Inspired by Villermen work, I created the library tseho/doctrine-assigned-identity which allows you to manually assign IDs to a Doctrine entity, even when the entity uses the stategies AUTO, SEQUENCE, IDENTITY or UUID.

You should never use it in production but it's really useful for functional tests.

The library will detect automatically the entities with an assigned id and replace the generator only when needed. The library will fallback on the initial generator when an instance does not have an assigned id.

The replacement of the generator occurs in a Doctrine EventListener, no need to add any additional code in your fixtures.

참고URL : https://stackoverflow.com/questions/5301285/explicitly-set-id-with-doctrine-when-using-auto-strategy

반응형