Композитный ключ и форма

У меня есть следующие ассоциации в моей базе данных (упрощенная версия):

дБ схема

Это ассоциация "многие ко многим", но с атрибутом в соединительной таблице, поэтому мне нужно использовать связи "один ко многим" и "многие к одному".

У меня есть форма, в которую я могу добавить столько отношений, сколько я хочу, к одному элементу заказа и создать его одновременно (главным образом, вдохновленный учебным пособием Как встраивать коллекцию форм из документации.

Когда я публикую форму, я получаю следующую ошибку:

Сущность типа TEST\MyBundle\Entity\Relation имеет идентификатор через внешнюю сущность TEST\MyBundle\Entity\Order, однако сама эта сущность не имеет идентификатора. Вы должны вызвать EntityManager#persist() для связанной сущности и убедиться, что идентификатор был сгенерирован, прежде чем пытаться сохранить 'TEST\MyBundle\Entity\Relation'. В случае генерации идентификатора после вставки (например, MySQL Auto-Increment или PostgreSQL SERIAL) это означает, что вы должны вызвать EntityManager#flush() между обеими операциями сохранения.

Я понимаю эту ошибку, потому что Доктрина пытается сохранить Relation объект (ы), связанные с заказом, так как у меня есть cascade={"persist"} вариант на OneToMany связь. Но как я могу избежать этого поведения?

Я пытался удалить cascade={"persist"} и вручную сохранить сущность, но я получаю ту же ошибку (потому что мне нужно flush() чтобы получить идентификатор, и когда я это делаю, у меня появляется то же сообщение об ошибке).
Я также пытался detach() Relation объекты до flush() но без удачи.

3 ответа

Решение

В итоге я создал отдельный первичный ключ на моем Relation стол (вместо составного).
Похоже, это грязное исправление, и я уверен, что есть лучший способ справиться с этой ситуацией, но пока это работает.

Вот мой Relations юридическое лицо:

/**
 * 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...

Затем я добавил cascade={"persist"} вариант на OneToMany связь с Order:

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

    //Rest of the entity...

И вуаля!

Эта проблема кажется уникальной, если 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, я не смог бы сохранить сущность OrderItem без предварительного сохранения сущности Order (так как doctrine/SQL требуется идентификатор заказа для составного ключа), но Doctrine EntityManager не позволил мне сохранить объект Order, который имеет Атрибуты OrderItem (потому что они настаивают на сохранении их вместе). Вы не можете отключить каскад, так как он будет жаловаться, что вы сначала не сохранили связанные объекты, и вы не сможете сохранить связанные объекты перед сохранением. 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 с двумя сторонними идентичностями в доктрине). Но это учение для вас, со всей своей силой, оно наверняка может связать вас. Но, к счастью, вам нужно будет сделать это только при создании нового объекта, а не при редактировании, потому что объект уже находится в базе данных.

Вам нужно сохранить и очистить оригинал, прежде чем вы сможете сохранить и очистить записи отношений. Вы на 100% правы в причине ошибки.

Я предполагаю из диаграммы, что вы пытаетесь добавить и порядок и отношение к контакту одновременно? Если это так, вам нужно сохранить и очистить заказ, прежде чем вы сможете сохранить и очистить отношения. Или вы можете добавить первичный ключ в таблицу отношений.

Другие вопросы по тегам