使用“AUTO”战略时,明确地设置标识与原则使用“AUTO”战略时,明确地设置标识与原则(Expli

2019-05-13 08:35发布

我的实体使用这个注释为它的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

Answer 1:

虽然您的解决方案做工精细与MySQL,我没有做它,因为它是基于序列可和PostgreSQL合作。

我已经加入这一行,使其很好地工作:

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

最好的祝福,



Answer 2:

也许什么主义改变,但是现在正确的做法是:

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


Answer 3:

如果该实体是部分类表继承 ,你需要更改类的元数据的ID发生器两个实体(你是坚持实体与根实体)



Answer 4:

新的解决方案正常工作,只有当所有的实体插入之前有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();
    }
}


Answer 5:

解决方案学说2.5和MySQL

“新的解决方案”不符合教义2.5和MySQL工作。 您必须使用:

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

但是我只能确认为MySQL,因为我还没有尝试过任何其他DBMS呢。



Answer 6:

我创建了一个图书馆以确定未来的ID为原则的实体。 它恢复到原来的ID生成策略时,所有排队的ID被消耗,尽量减少影响。 它应该是一个简单的插入式单元测试,以便像这样的代码没有重复。



Answer 7:

灵感来自Villermen工作中,我创建的库tseho /学说分配的身份 ,它允许你手动分配ID的学说实体,即使在实体使用策略及DCS AUTO,SEQUENCE,IDENTITY或UUID。

永远不应该使用它在生产 ,但它是功能测试非常有用。

该库将自动检测到实体分配的ID,并只在需要时更换发电机。 该库将回退到初始生成时的实例没有分配的ID。

更换发电机的学说事件监听时,无须电脑灯添加任何额外的代码。



文章来源: Explicitly set Id with Doctrine when using “AUTO” strategy