简体   繁体   中英

Symfony2 doctrine exception in persisting OneToMany entities

I configure this entities:

MarketMain:

class MarketMain
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="bigint", nullable=false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="IDENTITY")
     */
    private $id;

    /**
     * @var \Doctrine\Common\Collections\Collection
     *
     * @ORM\OneToMany(targetEntity="\Acme\CMSBundle\Entity\MarketLanguage", mappedBy="marketMain", indexBy="langId", cascade="all", orphanRemoval=true, fetch="EXTRA_LAZY")
     */
    private $marketLanguage;
}

MarketLanguage:

    class MarketLanguage
    {    
        /**
         * @var \Acme\CMSBundle\Entity\MarketMain
         * @ORM\Id
         * @ORM\ManyToOne(targetEntity="\Acme\CMSBundle\Entity\MarketMain", inversedBy="marketLanguage")
         * @ORM\JoinColumn(name="market_id", referencedColumnName="id")
         */
        private $marketMain;

        /**
         * @var integer
         *
         * @ORM\Id
         * @ORM\Column(name="lang_id", type="integer", nullable=false)
         */
        private $langId = 1;

        /**
         * @var string
         *
         * @ORM\Column(name="name", type="string", length=200, nullable=true)
         */
        private $name;
    }

And I want to save entity like this:

...........
    $form = $this->createForm(new MarketMainType(), new MarketMain());
    $form->handleRequest($request);
    $marketFormData = $form->getData();

    $em->persist($marketFormData);
    $em->flush($marketFormData);

    foreach ($marketFormData->getMarketLanguage() as $market_language)
    {
             $market_language->setName("My market name");
             $market_language->setMarketMain($marketFormData);
             $em->persist($market_language);
    }

    $em->flush();

Than I get this error:

Entity of type Acme\\CMSBundle\\Entity\\MarketLanguage is missing an assigned ID for field 'marketMain'. The identifier generation strategy for this entity requires the ID field to be populated before EntityManager#persist() is called. If you want automatically generated identifiers instead you need to adjust the metadata mapping accordingly.

If I trying to do $marketFormData persist after foreach statment I get this error:

Entity of type Acme\\CMSBundle\\Entity\\MarketLanguage has identity through a foreign entity Acme\\CMSBundle\\Entity\\MarketMain, 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 'Acme\\CMSBundle\\Entity\\MarketLanguage'. 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.

I know that If I try to persist $marketFormData before loop doctrine does not know the releated $marketLanguage references, but if I set persist after the foreach it says taht I have first persist parent entity. So I tried this code and it worked:

...........
    $form = $this->createForm(new MarketMainType(), new MarketMain());
    $form->handleRequest($request);
    $marketFormData = $form->getData();

    $market_languages = $marketFormData->getMarketLanguage();

    $marketFormData->setMarketLanguage(null);
    $em->persist($marketFormData);
    $em->flush($marketFormData);

    $marketFormData->setMarketLanguage($market_languages);
    foreach ($marketFormData->getMarketLanguage() as $market_language)
    {
             $market_language->setName("My market name");
             $market_language->setMarketMain($marketFormData);
             $em->persist($market_language);
    }

    $em->flush();

But it is only way to persist related entities? To clone it set to null, persist parent entity, and then set it back, add references and flush all. I think I have missed something here.

I think that your entities is mapped wrong. The entity must have an annotation about ID and another to relation.

And also, when you don't have a primary key with autoincrement, it is necessary declare the class constructor, passing both values as mentioned in http://doctrine-orm.readthedocs.org/en/latest/tutorials/composite-primary-keys.html

It should look like this:

class MarketLanguage
{
    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\Column(name="market_id", type="integer", nullable=false)
     */
    private $marketId;

    /**
     * @var integer
     *
     * @ORM\Id
     * @ORM\Column(name="lang_id", type="integer", nullable=false)
     */
    private $langId = 1;

    /**
     * @var \Acme\CMSBundle\Entity\MarketMain
     * 
     * @ORM\ManyToOne(targetEntity="\Acme\CMSBundle\Entity\MarketMain", inversedBy="marketLanguage")
     * @ORM\JoinColumn(name="market_id", referencedColumnName="id")
     */
    private $marketMain;

    /**
     * @var string
     *
     * @ORM\Column(name="name", type="string", length=200, nullable=true)
     */
    private $name;

    public function __construct($marketId, $langId) {
        $this->marketId = $marketId;
        $this->langId = $langId;
    }
}

Did you try remove flush($marketFormData) ?:

$form = $this->createForm(new MarketMainType(),$marketMain);
$form->handleRequest($request);
$marketFormData = $form->getData();

$em->persist($marketFormData);
// $em->flush($marketFormData); // remove that flush

foreach ($marketFormData->getMarketLanguage() as $market_language)
{
         $market_language->setName("My market name");
         $market_language->setMarketMain($marketMain);
         $em->persist($market_language);
}

$em->flush();

maybe problem is that you are trying flush $marketFormData which contains MarketLanguages which are not persised ? Not sure am i right, didn't tested this.

EDIT maybe this work:

$form = $this->createForm(new MarketMainType(), new MarketMain());
$form->handleRequest($request);
$marketFormData = $form->getData();

foreach ($marketFormData->getMarketLanguage() as $market_language)
{
         $market_language->setName("My market name");
         $market_language->setMarketMain($marketMain);
}

$em->persist($marketFormData);
$em->flush($marketFormData);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM