簡體   English   中英

Doctrine2一對多關系覆蓋整個集合

[英]Doctrine2 one-to-many relation overwrite whole collection

假設我有兩個實體Page和Block。 這是雙向映射。 每個頁面可以包含多個塊。 每個塊可以屬於單個頁面。

/**
 * @ORM\Entity
 * @ORM\Table(name="page")
 */
class Page
{
    ...
    /**
     * @ORM\OneToMany(targetEntity="Block", mappedBy="page", cascade={"all"}, orphanRemoval=true)
    **/
    private $blocks;
    ...
}

/**
 * @ORM\Entity
 * @ORM\Table(name="block")
 */
class Block
{
    ...
    /**
     * @ORM\ManyToOne(targetEntity="Page", inversedBy="blocks")
     * @ORM\JoinColumn(name="page_id", referencedColumnName="id")
     *
     **/
    private $page;
    ...
}

屬於頁面的塊有時會更改。 將添加一些塊,其中一些將被刪除。 下一種情況對我不起作用:

$page->setBlocks([1, 2, 3]);
$em->merge($page)
$em->flush() //Page will have blocks 1, 2, 3

$page->setBlocks([1, 4])
$em->merge($page)
$em->flush() //Page will have blocks 1, 2, 3, 4

在第二次flush()調用之后的預期結果是://頁面將具有1、4

因此,我需要使用merge方法完全覆蓋塊的集合。

約束:

  • 我無法在Page類中實現deleteBlock
  • 我只能在$ em上調用merge()和flush()

是否可以通過注釋或其他技巧來實現所需的結果?

解決約束

它不能用您的約束來完成。


建議的解決方案

我會在BlockRepository類中創建一個自定義函數,該函數刪除給定Page的所有塊,然后在調用setBlock函數之前先調用該函數。

將此添加到您的塊存儲庫類中:

public function deleteBlocksByPageId($page_id)
{
  $qb = $this->createQueryBuilder()
    ->delete('Block', 'b');
    ->where('b.page', ':page'));
    ->setParameter(':page', $page_id);

  $numDeleted = $qb->execute();

  return $numDeleted;
}

在您的控制器中:

//Delete all the existing blocks before adding them back in.
$repo = $this->getDoctrine()->getRepository('BundleName:BlockRepository');
$repo->deleteBlocksByPageId($page->getId());

$page->setBlocks([1, 4])
$em->merge($page)
$em->flush()

結論

這是管理經常更改的項目的常見模式。 它不需要循環。

如果約束是自我施加的,那么您需要放寬它們並找到另一種解決方案,例如我上面提供的解決方案。 如果他們是一些上流人士施加的限制,那么現在是時候與他/她進行對話,討論這種對話在這種情況下會適得其反。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM