持久化OneToMany实体中的Symfony2教义异常

时间:2015-02-06 12:42:51

标签: php entity-framework symfony doctrine-orm

我配置了这个实体:

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;
    }

我想保存这样的实体:

...........
    $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();

比我收到此错误:

  

Acme \ CMSBundle \ Entity \ MarketLanguage类型的实体缺少   为“marketMain”字段分配了ID。标识符生成策略   对于此实体,需要先填充ID字段   调用EntityManager#persist()。如果要自动生成   您需要调整元数据映射   相应

如果我在foreach语句之后试图$marketFormData继续存在,我会收到此错误:

  

Acme \ CMSBundle \ Entity \ MarketLanguage类型的实体具有标识   但是,通过外国实体Acme \ CMSBundle \ Entity \ MarketMain   这个实体本身没有身份。你必须打电话   EntityManager#persist()在相关实体上并确保一个   在尝试持久化之前生成了标识符   'Acme的\ CMSBundle \实体\ MarketLanguage'。如果是Post Insert ID   生成(如MySQL Auto-Increment或PostgreSQL SERIAL)这个   意味着你必须在两个persist之间调用EntityManager#flush()   操作

我知道如果我在循环学说之前尝试坚持$marketFormData并不知道相关的$marketLanguage引用,但是如果我在foreach之后设置持久,那么我说它首先坚持父实体。所以我尝试了这个代码,它起作用了:

...........
    $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();

但这只是坚持相关实体的方法吗?要将其克隆设置为null,请保留父实体,然后将其设置回来,添加引用并刷新所有内容。我想我在这里错过了什么。

2 个答案:

答案 0 :(得分:1)

我认为您的实体映射错误。实体必须具有关于ID的注释和关系的另一个注释。

而且,当你没有自动增量的主键时,必须声明类构造函数,传递http://doctrine-orm.readthedocs.org/en/latest/tutorials/composite-primary-keys.html中提到的两个值

它应该是这样的:

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;
    }
}

答案 1 :(得分:0)

您是否尝试过删除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();

也许问题是你正在尝试刷新$ marketFormData,其中包含没有持久化的MarketLanguages?不确定我是对的,没有测试过这个。

编辑也许这项工作:

$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);