español - Establecer explícitamente Id con Doctrine al usar la estrategia "AUTO"
doctrine tutorial español (6)
Aunque su solución funciona bien con MySQL, no pude hacerlo funcionar con PostgreSQL como está basado en secuencias.
Tengo que agregar esta línea para que funcione perfectamente:
$metadata->setIdGenerator(new /Doctrine/ORM/Id/AssignedGenerator());
Atentamente,
Mi entidad usa esta anotación para su ID:
/**
* @orm:Id
* @orm:Column(type="integer")
* @orm:GeneratedValue(strategy="AUTO")
*/
protected $id;
Desde una base de datos limpia, estoy importando en registros existentes de una base de datos anterior y tratando de mantener los mismos ID. Luego, cuando agregue nuevos registros, quiero que MySQL aumente automáticamente la columna ID como de costumbre.
Desafortunadamente, parece que Doctrine2 ignora por completo la ID especificada.
Nueva solución
Según las recomendaciones a continuación, la siguiente es la solución preferida:
$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());
Vieja solución
Debido a que Doctrine pivota fuera de ClassMetaData para determinar la estrategia del generador, debe modificarse después de administrar la entidad en EntityManager:
$this->em->persist($entity);
$metadata = $this->em->getClassMetaData(get_class($entity));
$metadata->setIdGeneratorType(/Doctrine/ORM/Mapping/ClassMetadata::GENERATOR_TYPE_NONE);
$this->em->flush();
Acabo de probar esto en MySQL y funcionó como se esperaba, es decir, las entidades con una ID personalizada se almacenaron con esa ID, mientras que las que no tienen una ID especificada utilizaron la lastGeneratedId() + 1
.
Creé una biblioteca para establecer identificaciones futuras para entidades de Doctrine. Se revierte a la estrategia de generación de ID original cuando se consumen todos los ID en cola para minimizar el impacto. Debería ser un complemento fácil para pruebas unitarias, de modo que no sea necesario repetir un código como este.
En el caso de que la entidad sea parte de una herencia de tabla de clase , debe cambiar el generador de ID en los metadatos de clase para ambas entidades (la entidad que está persistiendo y la entidad raíz)
La nueva solución funciona bien solo cuando TODAS las entidades tienen identificación antes de insertar. Cuando una entidad tiene ID y otra no, la nueva solución está fallando.
Uso esta función para importar todos mis datos:
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();
}
}
Tal vez lo que cambió la doctrina pero ahora es el camino correcto es:
$metadata->setIdGeneratorType(/Doctrine/ORM/Mapping/ClassMetadata::GENERATOR_TYPE_NONE);
Solución para Doctrine 2.5 y MySQL
La "Nueva solución" no funciona con Doctrine 2.5 y MySQL. Tienes que usar:
$metadata = $this->getEntityManager()->getClassMetaData(Entity::class);
$metadata->setIdGenerator(new AssignedGenerator());
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE);
Sin embargo, solo puedo confirmarlo para MySQL, porque aún no he probado ningún otro DBMS.