我的实体使用这个注释为它的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());
旧的解决方案
因为原则枢转关闭了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发生器两个实体(你是坚持实体与根实体)
新的解决方案正常工作,只有当所有的实体插入之前有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();
}
}
解决方案学说2.5和MySQL
“新的解决方案”不符合教义2.5和MySQL工作。 您必须使用:
$metadata = $this->getEntityManager()->getClassMetaData(Entity::class);
$metadata->setIdGenerator(new AssignedGenerator());
$metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_NONE);
但是我只能确认为MySQL,因为我还没有尝试过任何其他DBMS呢。
我创建了一个图书馆以确定未来的ID为原则的实体。 它恢复到原来的ID生成策略时,所有排队的ID被消耗,尽量减少影响。 它应该是一个简单的插入式单元测试,以便像这样的代码没有重复。
灵感来自Villermen工作中,我创建的库tseho /学说分配的身份 ,它允许你手动分配ID的学说实体,即使在实体使用策略及DCS AUTO,SEQUENCE,IDENTITY或UUID。
你永远不应该使用它在生产 ,但它是功能测试非常有用。
该库将自动检测到实体分配的ID,并只在需要时更换发电机。 该库将回退到初始生成时的实例没有分配的ID。
更换发电机的学说事件监听时,无须电脑灯添加任何额外的代码。