如何从嵌入式表单提交中保留实体?

时间:2014-04-22 13:00:23

标签: symfony doctrine-orm

我有Person实体和Address实体,设置为双向一对一关系,FK位于Address

...

class Person
{
    ...
    /**
     * @ORM\OneToOne(targetEntity="Address", mappedBy="person")
     */
    protected $address;
    ...
}

...

class Address
{
    ...
    /**
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="Person", inversedBy="address")
     * @ORM\JoinColumn(name="personID", referencedColumnName="id")
     */
    protected $person;
}

Address实体没有专用主键,而是通过与Person的外键关系派生其身份,explained here

我创建新Person的表单也嵌入了Address的表单。提交表单后,将执行此控制器操作:

public function createAction(Request $request)
{
    $person = new Person();

    $form = $this->createCreateForm($person);
    $form->handleRequest($request);

    if ($form->isValid()) {
        $em = $this->getDoctrine()->getManager();
        $em->persist($person);
        $em->flush();

        return $this->redirect($this->generateUrl('people'));
    }

    return array(
        'person' => $person,
        'form' => $form->createView(),
    );
}

我已检查过这些数据,$person的{​​{1}}属性已按预期填写了正确的表单详细信息。但是,一旦$address对象被持久化,我就会收到错误:

  

通过这种关系找到了一个新的实体   '的Acme \ AcmeBundle \实体\人#地址'没有配置   级联持久的实体操作......

我尝试过几件事似乎都没有效果:

  1. 在Person对象上的OneToOne关系定义上设置$person。这样做会导致错误:

      

    Acme \ AcmeBundle \ Entity \ Address类型的实体缺少已分配的实体   字段ID' ...

  2.   
  3. cascade={"persist"}方法上,我已采用Person#setAddress参数并手动调用$address。也不起作用。
  4.      看起来我的问题是Doctrine在保存$address->setPerson($this)对象之前试图保存Address对象,而且它不能因为它需要知道相关{{1}的ID首先。

    例如,如果我将持久化代码更改为类似的内容,则可以正常工作:

    Person

    我该如何正确地做到这一点?我希望保留使用这种一对一关系嵌入表单的能力,但事情开始变得复杂。如何在刷新Person对象之前让Doctrine刷新... // Pull out the address data and remove it from the Person object $address = $person->getAddress(); $person->setAddress(null); // Save the person object and flush so we get an ID $em->persist($person); $em->flush(); // Now set the person object on the address and save the address $address->setPerson($person); $em->persist($address); $em->flush(); ... 对象,而不像上面那样自己手动执行?

2 个答案:

答案 0 :(得分:4)

保持cascade = persist。

然后修改Person :: setAddress

class Person
{
    public function setAddress($address)
    {
        $this->address = $address;
        $address->setPerson($this); //*** This is what you are missing ***

这是一个非常常见的问题,但很难搜索。

答案 1 :(得分:1)

您的映射不正确。您在$ person上错误地使用@ORM\Id

如果还没有,请在地址中添加一个真实的$ id并再次添加`cascade = {" persist"}。

class Person
{
    ...
    /**
     * @ORM\OneToOne(targetEntity="Address", mappedBy="person", cascade={"persist"})
     */
    protected $address;
    ...
}

...

class Address
{
    ...
    /**
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\OneToOne(targetEntity="Person", inversedBy="address")
     * @ORM\JoinColumn(name="personID", referencedColumnName="id")
     */
    protected $person;
}

如果Person是拥有者,地址也应该由Doctrine自动保留,不知道你的模型,但也许你应该考虑更改它。