例如,我有以下两个类(为简洁起见省略了getter/setter),它们在映射中是双向链接的:
class Form
{
private $elements = array();
public function addElement($element)
{
$this->elements[] = $element
$element->setForm($this);
}
}
class Element
{
private $form;
private $name;
}
<one-to-many field="elements" target-entity="Element" mapped-by="form"/>
<many-to-one field="form" target-entity="Form" inversed-by="elements">
<join-column name="formId" referenced-column-name="id" on-delete="CASCADE" on-update="CASCADE"/>
</many-to-one>
如果我执行以下操作;向表单添加两个元素,但只持久化一个元素,我希望发生的是实体管理器完全忽略未持久化的元素,但将另一个元素和表单插入到数据库中:
$form = new Form;
$em->persist($form);
$element = new Element;
$element->setName('firstName');
$form->addElement($element);
$em->persist($element);
$element2 = new Element;
$element2->setName('lastName');
$form->addElement($element2);
$em->flush();
目前得到以下错误:
exception 'Doctrine'ORM'ORMInvalidArgumentException' with message 'A new entity was found through the relationship 'Form#elements' that was not configured to cascade persist operations for entity Element@0000000019217f52000000009c20d747. To solve this issue: Either explicitly call EntityManager#persist() on this unknown entity or configure cascade persist this association in the mapping for example @ManyToOne(..,cascade={"persist"}). If you cannot find out which entity causes the problem implement 'Element#__toString()' to get a clue
据我所知,没有级联选项来忽略新实体(http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/working-with-associations.html#transitive-persistence-cascade-operations),并且使用preUpdate生命周期回调从$elements数组中删除违规实体也不起作用,因为在回调运行之前抛出异常。
有什么办法吗?
尝试只刷新需要的实体:
$form = new Form;
$em->persist($form);
$em->flush($form);
$element = new Element;
$element->setName('firstName');
$form->addElement($element);
$em->persist($element);
$em->flush($element);
//ignored element
$element2 = new Element;
$element2->setName('lastName');
$form->addElement($element2);
因为这是我能找到的唯一与这个问题相关的页面,所以我将添加我自己想到的解决方案。(在我的项目中,它基本上也是一个带有答案的表单,在那里我手动保存已更新的答案,但不完整的答案不应该在持久化表单时保存到数据库。)
基本上,您为关系创建了两个属性:一个仅用于加载持久化的相关元素($subEntities
),另一个将向公众提供($chachedSubEntities
)。
这个$cachedSubEntities
成员将在你第一次调用getSubEntities
时被持久化的子实体初始化。
class MyEntity extends AbstractEntity
{
/**
* @ORM'OneToMany(targetEntity="SubEntity", mappedBy="parent", indexBy="id")
*/
protected $subEntities;
protected $cachedSubEntities;
public function __construct()
{
$this->subEntities = new ArrayCollection();
}
public function getSubEntities()
{
if (is_null($this->cachedSubEntities)) {
$this->cachedSubEntities = new ArrayCollection($this->subEntities->toArray());
}
return $this->cachedSubEntities;
}
}