2016-06-07 117 views
0

背景信息的Symfony2 + Doctrine2:实体去除效果集合

我有一个名为年报与多个集合的实体(假设2为简洁的缘故)。的这些集合的一个排在FormType自动处理:

 //AnnualReportStaffing entity collection 
     ->add('staffingTenured', 'collection', array(
      'type' => new AnnualReportStaffingType(), 
      'allow_add' => true, 
      'allow_delete' => true, 
      'by_reference' => false, 
     )) 

其他集合是文件和删除的集合不是自动处理:

 //AnnualReportDetail entity collection 
     ->add('documents', 'collection', array(
      'type' => new AnnualReportDocumentType(), 
      'allow_add' => true, 
      'allow_delete' => false, // Do NOT automatically remove documents not in the collection (i.e. edit form where Documents are not passed again) 
      'by_reference' => false, 
     )) 

这是我的AnnualReport实体类中每个集合的属性/方法声明:

/** 
* @ORM\ManyToMany(targetEntity="AnnualReportStaffing", cascade={"persist", "detach", "remove"}, orphanRemoval=true, fetch="LAZY") 
* @ORM\JoinTable(name="annualreports_staffingtenure", 
*  joinColumns={@ORM\JoinColumn(name="annualreport_id", referencedColumnName="id")}, 
*  inverseJoinColumns={@ORM\JoinColumn(name="staffing_id", referencedColumnName="id", onDelete="CASCADE")}, 
*  ) 
*/ 
private $staffingTenured; 

/** 
* @ORM\ManyToMany(targetEntity="Document", cascade={"persist", "detach", "remove"}, orphanRemoval=true, fetch="LAZY") 
* @ORM\JoinTable(name="annualreports_documents", 
*  joinColumns={@ORM\JoinColumn(name="annualreport_id", referencedColumnName="id")}, 
*  inverseJoinColumns={@ORM\JoinColumn(name="document_id", referencedColumnName="id", onDelete="CASCADE")}, 
*  ) 
*/ 
private $documents; 

public function __construct(AnnualReportUnit $unit, $year) { 
    $this->staffingTenured = new ArrayCollection(); 
    $this->documents = new ArrayCollection(); 
} 

/** 
* Add staffingTenured 
* 
* @param AppBundle\Entity\AnnualReportStaffing $staffing 
* @return AnnualReport 
*/ 
public function addStaffingTenured(AnnualReportStaffing $staffing) 
{ 
    $this->staffingTenured->add($staffing); 

    return $this; 
} 

/** 
* Remove staffingTenured 
* 
* @param AppBundle\Entity\AnnualReportStaffing $staffing 
* @return AnnualReport 
*/ 
public function removeStaffingTenured(AnnualReportStaffing $staffing) 
{ 
    $this->staffingTenured->removeElement($staffing); 

    return $this; 
} 

/** 
* Get staffingTenured 
* 
* @return ArrayCollection 
*/ 
public function getStaffingTenured() 
{ 
    return $this->staffingTenured; 
} 

/** 
* Add document 
* 
* @param AppBundle\Entity\AnnualReportDocument $document 
* @return AnnualReport 
*/ 
public function addDocument(AnnualReportDocument $document) 
{ 
    $this->documents->add($document); 

    return $this; 
} 

/** 
* Remove document 
* 
* @param AppBundle\Entity\AnnualReportDocument $document 
* @return AnnualReport 
*/ 
public function removeDocument(AnnualReportDocument $document) 
{ 
    $this->documents->removeElement($document); 

    return $this; 
} 

/** 
* Get documents 
* 
* @return ArrayCollection 
*/ 
public function getDocuments() 
{ 
    return $this->documents; 
} 

问题

当谈到时间删除年报实体:

  • 如果文件存在,我能够删除的文件集合,但我得到了一个外键约束错误员工保险项目。
An exception occurred while executing 'DELETE FROM annual_report WHERE id = ?' with params [57]: 

SQLSTATE[23000]: Integrity constraint violation: 1451 Cannot delete or update a parent row: a foreign key constraint fails 

libcommandannualreports_staffingtenure,约束 FK_DB56517AD4F67A27外键(annualreport_id)参考文献 annual_reportid))

  • 如果没有文件都存在,年报实体和所有人员配备保密项目按预期被删除。

这是deleteAction():

public function deleteAction(Request $request, $id) 
{ 
    $requestData = $request->request->all(); 
    $unit = $requestData['form']['unit']; 


    $form = $this->createDeleteForm($id); 
    $form->handleRequest($request); 

    if ($form->isValid()) { 
     $em = $this->getDoctrine()->getManager(); 
     $entity = $em->getRepository('AppBundle:AnnualReport')->find($id); 

     if (!$entity) { 
      throw $this->createNotFoundException('Unable to find AnnualReport entity.'); 
     } 

     //Remove any documents (allow_delete set to FALSE in form so have to do manually) 
     $documents = $entity->getDocuments(); 
     foreach($documents as $document){ 
      $entity->removeDocument($document); 
      //$em->remove($document); 
     } 
     $em->persist($entity); 
     $em->flush(); 

     $em->remove($entity); 
     $em->flush(); //flush again to remove the annual report 
    } 

    return $this->redirect($this->generateUrl('annualreportunit_edit', array('id' => $unit))); 
} 

回答

1

您在这里混合形式和ORM。 allow_delete是表单的参数,这意味着它用于处理表单。

因为symfony的doc说的allow_delete

如果设置为true,那么如果现有的项目没有在提交的数据包含,这将是从项目的最终阵列正确地缺席。 这意味着你可以通过JavaScript实现一个“删除”按钮,它只是从DOM中删除一个表单元素。当用户提交表单时,它不在提交的数据中意味着它从最终数组中移除。

因此,它可以用来实现以的形式从根实体中移除收集项的可能性。但这并不意味着教义也会神奇地处理它。

如果您希望子实体在父实体时被保存/删除,您应该使用cascade属性中的实体映射

+0

这是形式和ORM之间的差异的精细解释,但问题是,我使用级联在我的实体映射并正确级联人员配备实体时我也不必手动删除文档实体。只有在这种情况下,它不起作用。 – Ravioli87

0

你如何捕捉ForeignKeyConstraintViolationException异常或更好的捕获DBALException。然后向用户显示错误。或者当您捕获异常时,您可以删除子节点,然后再次删除该实体。

use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
或者
use Doctrine\DBAL\DBALException;

try { 
    $em->remove($entity); 
    $em->flush(); 

    $this->addFlash('success', 'Removed'); 
} catch (DBALException $e) { 
    $em->remove($childEntity); 
    $em->flush(); 

    $em->remove($entity); 
    $em->flush(); 
--OR-- 
} catch (ForeignKeyConstraintViolationException $e) { 
    $em->remove($childEntity); 
    $em->flush(); 

    $em->remove($entity); 
    $em->flush(); 
}