Symfony3.4.6+FOSRestBundle:Ajax API提交时Cascade Persist不生效
我来帮你排查并解决这个问题——双向关联下cascade={"persist"}失效,大概率是关联维护逻辑或序列化处理的问题,咱们一步步来:
1. 先修复双向关联的核心逻辑
你在Embarque::addEmbarqueContenedor里注释掉了关键的关联维护代码,这是Doctrine识别关联关系的核心:
//$embarqueContenedor->setEmbarque($this);
在双向一对多关联中,必须同时维护两边的引用,否则Doctrine无法识别这个EmbarqueContenedor属于当前Embarque实例,自然不会触发级联持久化。赶紧恢复这行代码:
public function addEmbarqueContenedor($embarqueContenedor) { if (!$this->contenedores->contains($embarqueContenedor)) { $this->contenedores->add($embarqueContenedor); $embarqueContenedor->setEmbarque($this); // 取消注释,恢复关联维护 } }
同理,Contenedor::addEmbarqueContenedor方法也要补全$embarqueContenedor->setContenedor($this);,确保双向关联的完整性。
2. 处理API提交时的序列化/反序列化问题
因为是Ajax提交API,FOSRestBundle依赖Symfony Serializer处理请求体,这里容易出现关联丢失的情况:
- 如果你的请求JSON里没有传递
embarque字段(毕竟它属于正在创建的Embarque),反序列化后的EmbarqueContenedor实例的$embarque属性会是null,这时候即使你在add方法里设置了,也要在控制器中手动兜底处理:
public function createEmbarqueAction(Request $request) { $em = $this->getDoctrine()->getManager(); $serializer = $this->get('serializer'); // 反序列化请求体到Embarque实例 $embarque = $serializer->deserialize( $request->getContent(), Embarque::class, 'json' ); // 手动确保每个关联的EmbarqueContenedor都绑定当前Embarque foreach ($embarque->getContenedores() as $ec) { $ec->setEmbarque($embarque); // 如果请求里传了Contenedor的ID,还要从数据库捞取实例绑定 // $contenedor = $em->getRepository(Contenedor::class)->find($ec->getContenedor()->getId()); // $ec->setContenedor($contenedor); } $em->persist($embarque); $em->flush(); // 返回响应... }
3. 验证Doctrine映射的完整性
检查EmbarqueContenedor的关联映射是否完整,比如$embarque字段要加上@ORM\JoinColumn注解,确保外键约束正确生成:
/** * @var Embarque * * @ORM\ManyToOne(targetEntity="AppBundle\Entity\Embarque", inversedBy="contenedores") * @ORM\JoinColumn(name="embarque_id", referencedColumnName="id", nullable=false) // 补充这行 */ private $embarque;
没有这个注解的话,Doctrine可能无法正确识别外键关联,导致级联逻辑失效。
4. 确认请求数据格式正确
你的请求JSON要符合序列化规则,比如创建带关联的Embarque时,结构大概是这样:
{ "contenedores": [ { "contenedor": {"id": 1} // 关联已存在的Contenedor,传递ID即可 } ] }
如果要同时创建新的Contenedor,需要给EmbarqueContenedor的$contenedor关联也加上cascade={"persist"}。
按以上步骤修复后,cascade={"persist"}应该就能正常触发,关联的EmbarqueContenedor会和Embarque一起被持久化到数据库。
内容的提问来源于stack exchange,提问作者Juan I. Morales Pestana

