2016-06-07 38 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(); 
} 
相關問題