假设我有两个实体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()调用后的预期结果是:// Page将有1,4
所以我需要用merge方法覆盖完整的块集合。
约束:
是否可以通过注释或其他技巧实现所需的结果?
答案 0 :(得分:0)
您的约束不能完成。
我在BlockRepository类中创建一个自定义函数,删除给定Page的所有块,然后在调用setBlock函数之前调用该函数。
将此添加到您的Block Repository类:
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()
这是管理经常更改的项目的常见模式。它不需要循环。
如果约束是自我施加的,那么你需要放松它们并找到另一种解决方案,例如我上面提供的解决方案。如果他们受到某些高层人员的限制,那么是时候和他/她谈谈在这种情况下它会产生反作用。