如果 1) 您正在使用带有复合键的连接表,2) 表单组件,以及 3) 连接表是由表单组件的“集合”字段构建的实体,则这个问题似乎是独一无二的。我看到很多人遇到问题但没有很多解决方案,所以我想我会分享我的。
我想保留我的复合主键,因为我想确保两个外键中只有一个实例会保留在数据库中。以此
实体设置为例
/** @Entity */
class Order
{
/** @OneToMany(targetEntity="OrderItem", mappedBy="order") */
private $items;
public function __construct(Customer $customer)
{
$this->items = new Doctrine\Common\Collections\ArrayCollection();
}
}
/** @Entity */
class Product
{
/** @OneToMany(targetEntity="OrderItem", mappedBy="product") */
private $orders;
.....
public function __construct(Customer $customer)
{
$this->orders = new Doctrine\Common\Collections\ArrayCollection();
}
}
/** @Entity */
class OrderItem
{
/** @Id @ManyToOne(targetEntity="Order") */
private $order;
/** @Id @ManyToOne(targetEntity="Product") */
private $product;
/** @Column(type="integer") */
private $amount = 1;
}
我面临的问题是,如果我Order
在表单中构建一个对象,该对象的集合字段为OrderItem
s,我将无法在没有先保存 Order 实体的情况下保存 OrderItem 实体(因为学说/SQL 需要订单 ID对于复合键),但 Doctrine EntityManager 不允许我保存具有 OrderItem 属性的 Order 对象(因为它坚持将它们一起保存)。您不能关闭级联,因为它会抱怨您没有先保存关联实体,并且您无法在保存之前保存关联实体Order
。真是个难题。 我的解决方案是删除关联实体,保存Order
然后将关联实体重新引入 Order 对象并再次保存. 所以首先我创建了一个 ArrayCollection 属性的质量分配函数$items
class Order
{
.....
public function setItemsArray(Doctrine\Common\Collections\ArrayCollection $itemsArray = null){
if(null){
$this->items->clear();
}else{
$this->items = $itemsArray;
}
....
}
然后在我的控制器中处理订单表格。
//get entity manager
$em = $this->getDoctrine()->getManager();
//get order information (with items)
$order = $form->getData();
//pull out items array from order
$items = $order->getItems();
//clear the items from the order
$order->setItemsArray(null);
//persist and flush the Order object
$em->persist($order);
$em->flush();
//reintroduce the order items to the order object
$order->setItemsArray($items);
//persist and flush the Order object again ):
$em->persist($order);
$em->flush();
您必须坚持并刷新两次,这很糟糕(请参阅此处的更多信息Persist object with two foreign identities in dictionary)。但这对你来说是教义,凭借它的全部力量,它肯定会让你陷入困境。但幸运的是,您只需在创建新对象时执行此操作,而不是编辑,因为该对象已经在数据库中。