我有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 \实体\人#地址'没有配置 级联持久的实体操作......
我尝试过几件事似乎都没有效果:
$person
。这样做会导致错误:
Acme \ AcmeBundle \ Entity \ Address类型的实体缺少已分配的实体 字段ID' ...
cascade={"persist"}
方法上,我已采用Person#setAddress
参数并手动调用$address
。也不起作用。$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();
...
对象,而不像上面那样自己手动执行?
答案 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自动保留,不知道你的模型,但也许你应该考虑更改它。