Persist object with two foreign identities in doctrine

假如想象 提交于 2019-12-12 13:50:15

问题


I have created an entity using the yml-syntax in my symfony bundle, in the Resources/config/doctrine folder:

Sulu\Bundle\TranslateBundle\Entity\Translation:
type: entity
table: tr_translations
id:
    code:
        type: string
        column: idCodes
        associationKey: id
    catalogue:
        type: string
        column: idCatalogues
        associationKey: id
fields:
    value:
        type: text
manyToOne:
    code:
        targetEntity: Code
        inversedBy: tr_codes
        joinColumn:
            name: idCodes
            referencedColumnName: id
    catalogue:
        targetEntity: Catalogue
        inversedBy: tr_catalogues
        joinColumn:
            name: idCatalogues
            referencedColumnName: id

This part is working correctly. But when I create some objects like in the following code, I get an error message that I have to use the flush method, in order to get IDs for the foreign keys.

This is the code snippet I am currently using:

    // create a new package and catalogue for the import
    $package = new Package();
    $package->setName($this->getName());
    $catalogue = new Catalogue();
    $catalogue->setLocale($this->getLocale());
    $catalogue->setPackage($package);

    $this->em->persist($package);
    $this->em->persist($catalogue);

    // load the file, and create a new code/translation combination for every message
    $fileCatalogue = $loader->load($this->getFile(), $this->getLocale());
    foreach ($fileCatalogue->all()['messages'] as $key => $message) {
        $code = new Code();
        $code->setPackage($package);
        $code->setCode($key);
        $code->setBackend(true);
        $code->setFrontend(true);

        $translate = new Translation();
        $translate->setCode($code);
        $translate->setValue($message);
        $translate->setCatalogue($catalogue);

        $this->em->persist($code);
        $this->em->flush(); //FIXME no flush in between, if possible
        $this->em->persist($translate);
    }

    // save all the changes to the database
    $this->em->flush();

If I don't call the flush in the foreach loop I get the following error, which I totally understand, but isn't there a more elegant solution for this problem?

Doctrine\ORM\ORMException : Entity of type Sulu\Bundle\TranslateBundle\Entity\Translation has identity through a foreign entity Sulu\Bundle\TranslateBundle\Entity\Code, however this entity has no identity itself. You have to call EntityManager#persist() on the related entity and make sure that an identifier was generated before trying to persist 'Sulu\Bundle\TranslateBundle\Entity\Translation'. In case of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call EntityManager#flush() between both persist operations.


回答1:


Unfortunately, as per Doctrine Docs you have to call flush to get IDs for your foreign keys:

Generated entity identifiers / primary keys are guaranteed to be available after the next successful flush operation that involves the entity in question. You can not rely on a generated identifier to be available directly after invoking persist. The inverse is also true. You can not rely on a generated identifier being not available after a failed flush operation.




回答2:


Have you tried something like the following?

YAML:

Sulu\Bundle\TranslateBundle\Entity\Translation:
type: entity
table: tr_translations
id:
    code:
        type: string
        column: idCodes
        associationKey: id
    catalogue:
        type: string
        column: idCatalogues
        associationKey: id
fields:
    value:
        type: text
manyToOne:
    code:
        targetEntity: Code
        cascade: ["persist"]
        inversedBy: tr_codes
        joinColumn:
            name: idCodes
            referencedColumnName: id
    catalogue:
        targetEntity: Catalogue
        cascade: ["persist"]
        inversedBy: tr_catalogues
        joinColumn:
            name: idCatalogues
            referencedColumnName: id

In your class Translation

public function __construct()
{
    $this->code = new \Doctrine\Common\Collections\ArrayCollection();
    $this->catalogue = new \Doctrine\Common\Collections\ArrayCollection();
}

public function addCatalogue($catalogue)
{
    $this->catalogue[] = $catalogue;

    return $this;
}

public function addCode($code)
{
    $this->code[] = $code;

    return $this;
}

Then your code can be something like this:

$package = new Package();
$package->setName($this->getName());
$catalogue = new Catalogue();
$catalogue->setLocale($this->getLocale())->setPackage($package);

$fileCatalogue = $loader->load($this->getFile(), $this->getLocale());
foreach ($fileCatalogue->all()['messages'] as $key => $message) {
    $code = new Code();
    $code->setPackage($package)
         ->setCode($key)
         ->setBackend(true)
         ->setFrontend(true);
    $translate = new Translation();
    $translate->addCode($code)
              ->setValue($message)
              ->addCatalogue($catalogue);
    $this->em->persist($translate);
}

$this->em->flush();

Note: cascade: ["persist"] - Cascades persist operations to the associated entities. Link



来源:https://stackoverflow.com/questions/18143630/persist-object-with-two-foreign-identities-in-doctrine

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!