Symfony 如何从嵌入式表单提交中持久化实体?
我有一个Symfony 如何从嵌入式表单提交中持久化实体?,symfony,doctrine-orm,Symfony,Doctrine Orm,我有一个人实体和一个地址实体,通过双向一对一关系设置,FK位于地址: ... class Person { ... /** * @ORM\OneToOne(targetEntity="Address", mappedBy="person") */ protected $address; ... } ... class Address { ... /** * @ORM\Id * @ORM\OneToOne
人
实体和一个地址
实体,通过双向一对一关系设置,FK位于地址
:
...
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;
}
地址
实体没有专用的主键,而是通过与人员
的外键关系派生其身份,如下所示
我用来创建一个新人的表单也嵌入了地址表单。提交表单时,将执行此控制器操作:
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
的$address
属性按照预期填写了正确的表单详细信息。但是,一旦保存了$person
对象,就会出现以下错误:
通过关系找到了一个新实体
“Acme\AcmeBundle\Entity\Person#address”未配置为
实体的级联持久化操作
我试过几种方法,但似乎都不管用:
cascade={“persist”}
。这样做会导致错误:
Acme\AcmeBundle\Entity\Address类型的实体缺少分配的
字段“person”的IDPerson#setAddress
方法中,我使用了$address
参数,并在其上手动调用了$address->setPerson($this)
。也不行人
对象之前保存地址
对象,但它不能,因为它需要先知道关联的人
的ID
例如,如果我将persist代码更改为如下内容,它将起作用:
...
// 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();
...
我怎样才能正确地做到这一点?我想保留嵌入具有这种一对一关系的表单的能力,但事情开始变得复杂起来。在刷新
$address
对象之前,如何让Doctrine刷新$person
对象,而不必像上面那样手动执行该操作?保持cascade=persist
然后修改Person::setAddress
class Person
{
public function setAddress($address)
{
$this->address = $address;
$address->setPerson($this); //*** This is what you are missing ***
这是一个非常常见的问题,但很难搜索。您的映射不正确。您在$person上错误地使用了
@ORM\Id
如果您还没有,请向Address添加一个真正的$id,然后再次添加`cascade={“persist”}
如果人是拥有方,地址也应该被理论自动保留,不知道你的模型,但也许你应该考虑改变它。
我实际上不想在<代码>地址< />代码中添加一个专用的主键。请参见以下说明:我使用外键作为地址的主键我更新了我的问题,以包含我原本应该做的详细信息。这导致错误:类型为Acme\AcmeBundle\Entity\Address的实体通过外部实体Acme\AcmeBundle\Entity\Person具有标识,然而,这个实体本身没有身份。您必须在相关实体上调用EntityManager#persist(),并确保在尝试持久化“Acme\AcmeBundle\entity\DetailsCS”之前生成了标识符。在生成插入后ID(如MySQL自动增量或PostgreSQL串行)的情况下,这意味着您必须在两个持久化操作之间调用EntityManager#flush()。基于这个有用的错误,我可能确实需要使用我的“变通方法”,我会给地址实体它自己的简单自动递增id,并使person成为常规关系而不是主id。是的,它是一个额外的数据库列,但我想你会发现它节省了很多麻烦。
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;
}