[doctrine] “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);

그러나 아직 다른 DBMS를 시도하지 않았기 때문에 MySQL에 대해서만 확인할 수 있습니다.


답변

Doctrine 엔티티에 대한 향후 ID를 설정 하는 라이브러리 를 만들었습니다 . 영향을 최소화하기 위해 대기중인 모든 ID가 소비되면 원래 ID 생성 전략으로 되돌아갑니다. 이와 같은 코드를 반복 할 필요가 없도록 단위 테스트를위한 쉬운 드롭 인이어야합니다.


답변

Villermen 작업에서 영감을 받아 , 엔티티가 AUTO, SEQUENCE, IDENTITY 또는 UUID 상태를 사용하는 경우에도 Doctrine 엔티티에 ID를 수동으로 할당 할 수 있는 라이브러리 tseho / doctrine-assigned-identity 를 만들었습니다 .

당신은 생산에 사용해서는 안 하지만, 기능 테스트 정말 유용합니다.

라이브러리는 할당 된 ID가있는 엔티티를 자동으로 감지하고 필요한 경우에만 생성기를 교체합니다. 인스턴스에 할당 된 ID가없는 경우 라이브러리는 초기 생성기를 대체합니다.

생성기 교체는 Doctrine EventListener에서 발생하므로 조명기에 추가 코드를 추가 할 필요가 없습니다.