Symfony 组合键和窗体

Symfony 组合键和窗体,symfony,doctrine-orm,symfony-2.2,Symfony,Doctrine Orm,Symfony 2.2,我的数据库中有以下关联(简化版): 这是一个多对多关联,但在联接表上有一个属性,所以 我有一个表单,我可以在其中添加任意多个关系到一个订单项,并同时创建它(主要受文档中教程的启发) 当我发布表单时,出现以下错误: 类型为TEST\MyBundle\Entity\Relation的实体通过具有标识 外部实体TEST\MyBundle\entity\Order,但此实体 本身没有标识。必须在上调用EntityManager#persist() 并确保生成了标识符 在尝试持久化“TEST\MyBun

我的数据库中有以下关联(简化版):

这是一个多对多关联,但在联接表上有一个属性,所以

我有一个表单,我可以在其中添加任意多个关系到一个订单项,并同时创建它(主要受文档中教程的启发)

当我发布表单时,出现以下错误:

类型为TEST\MyBundle\Entity\Relation的实体通过具有标识 外部实体TEST\MyBundle\entity\Order,但此实体 本身没有标识。必须在上调用EntityManager#persist() 并确保生成了标识符 在尝试持久化“TEST\MyBundle\Entity\Relation”之前。如果 插入后ID生成(如MySQL自动增量或 这意味着您必须调用EntityManager#flush() 在两个持久化操作之间

我理解这个错误是因为条令试图持久化与顺序相关的
关系
对象,因为我在
OneToMany
关系上有
cascade={“persist”}
选项。但是我如何避免这种行为呢

我试图删除
cascade={“persist”}
并手动持久化实体,但我得到了相同的错误(因为我需要
flush()
才能获得ID,当我这样做时,我得到了相同的错误消息)。

我还尝试在
flush()
之前
detach()
分离
关系
对象,但没有成功。

您需要先保留并刷新原始对象,然后才能保留并刷新关系记录。错误原因100%正确


从图表中,我假设您正试图同时添加和排序以及与联系人的关系?如果是这样,您需要先保留和刷新订单,然后才能保留和刷新关系。或者您可以向关系表添加主键。

我最终在我的
关系表上创建了一个单独的主键e(而不是复合的)。
这看起来像是一个肮脏的修复,我相信有更好的方法来处理这种情况,但它现在起作用

这是我的
关系
实体:

/**
 * Relation
 *
 * @ORM\Entity
 */
class Relation
{
    /**
     * @var integer
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\ManyToOne(targetEntity="Contact", inversedBy="relation")
     */
    protected $contact;

    /**
     * @ORM\ManyToOne(targetEntity="Order", inversedBy="relation")
     */
    protected $order;

    /**
     * @var integer
     *
     * @ORM\Column(name="invoice", type="integer", nullable=true)
     */
    private $invoice;

    //Rest of the entity...
然后,我在与
Order
OneToMany
关系中添加了
cascade={“persist”}
选项:

/**
 * Orders
 *
 * @ORM\Entity
 */
class Order
{   
    /**
     * @ORM\OneToMany(targetEntity="Relation", mappedBy="order", cascade={"persist"})
     */
    protected $relation;

    //Rest of the entity...

Et voilá!

如果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;
}
我所面临的问题是,如果我在表单中构建一个集合字段为
OrderItem
s的
Order
对象,如果不先保存Order实体,我将无法保存OrderItem实体(因为doctor/SQL需要复合键的Order id),但是Doctrine EntityManager不允许我保存具有OrderItem属性的Order对象(因为它坚持将它们一起保存)。您不能关闭cascade,因为它会抱怨您没有首先保存关联的实体,并且您不能在保存订单之前保存关联的实体。真是个难题我的解决方案是删除关联的实体,保存
Order
,然后将关联的实体重新引入Order对象并再次保存。首先,我创建了一个ArrayCollection属性的mass赋值函数
$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”}
,如果我把它放回去,它会首先尝试保存关系。你在什么地方有工作的例子吗?我找不到一个…你需要手动保持关系。
cascade={“persist”}
所做的一切就是,如果你将一个实体与该集合保持关系,它将自动添加
$em->persist($relationshipObject)
,因此要解决你的问题,你需要关闭它,手动保持关系对象,并进行第二次刷新={“persist”}
然后首先persist/flush order对象,我得到一个:
通过关系“TEST\MyBundle\entity\Orders\relations”找到了一个新实体,该关系没有配置为级联实体的persist操作:TEST\MyBundle\entity\relations…
。我甚至尝试使用
detach()
在关系对象上,但未成功。。。