Explicitly set Id with Doctrine when using “AUTO” strategy

前端 未结 7 697
时光说笑
时光说笑 2020-12-02 05:36

My entity uses this annotation for it\'s ID:

/**
 * @orm:Id
 * @orm:Column(type=\"integer\")
 * @orm:GeneratedValue(s         


        
相关标签:
7条回答
  • 2020-12-02 05:53

    In case the entity is part of a class table inheritance you need to change the id-generator in the class metadata for both entities (the entity you are persisting and the root entity)

    0 讨论(0)
  • 2020-12-02 05:58

    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.

    0 讨论(0)
  • 2020-12-02 05:59

    New solution works fine only when ALL entities have id before insert. When one entity has ID and another one does not - new solution is failing.

    I use this function for import all my data:

    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();
        }
    }
    
    0 讨论(0)
  • 2020-12-02 06:08

    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.

    0 讨论(0)
  • 2020-12-02 06:14

    Perhaps what doctrine changed but now right way is:

    $metadata->setIdGeneratorType(\Doctrine\ORM\Mapping\ClassMetadata::GENERATOR_TYPE_NONE);
    
    0 讨论(0)
  • 2020-12-02 06:15

    Solution for Doctrine 2.5 and MySQL

    The "New solution" doesn't work with Doctrine 2.5 and MySQL. You have to use:

    $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.

    0 讨论(0)
提交回复
热议问题