2013-04-09 3 views
5

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

db schema

Это многие-ко-многим ассоциации, но с атрибутом присоединяющейся стола, так I have to use One-To-Many/Many-To-One associations.

У меня есть форма, где я могу добавить столько отношения, как я хочу, чтобы один пункт заказа и создать его в то же время (в основном вдохновлен How to Embed a Collection of Forms учебник от документации.

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

Entity of type TEST\MyBundle\Entity\Relation has identity through a foreign entity TEST\MyBundle\Entity\Order, however this entity has no identity itself. You have to call EntityManager#persist() on the related entity and make sure that an identifier was generated before trying to persist 'TEST\MyBundle\Entity\Relation'. In case of Post Insert ID Generation (such as MySQL Auto-Increment or PostgreSQL SERIAL) this means you have to call EntityManager#flush() between both persist operations.

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

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

ответ

1

Я закончил создание разделенного первичного ключа на моей 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

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

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

+0

Вы правы, я пытаюсь добавить заказ и отношение для контакта в одно и то же время. Я попытался очистить порядок раньше, но затем я получаю сообщение об ошибке 'cascade = {" persist "}', и если я верну его, он попытается сначала сохранить отношение. У вас есть рабочий пример? Я не могу найти один ... – cheesemacfly

+0

вам нужно вручную сохранить отношения. Все 'cascade = {" persist "}' есть, если вы сохраняете сущность с отношением с этим набором, она автоматически добавит '$ em-> persist ($ relationshipObject)' Итак, чтобы исправить вашу проблему, вам нужно будет оставить это выключить и вручную сохранить объекты отношений и сделать второй сброс. –

+0

Но если я попытаюсь удалить 'cascade = {" persist "}', а затем сначала перенести/очистить объект заказа, я получаю a: 'Новый объект был найден через отношение TEST \ MyBundle \ Entity \ Orders # relations ' который не был настроен на каскадное сохранение операций для объекта: TEST \ MyBundle \ Entity \ Relations ... '. Я даже пытался использовать 'detach()' на объекте отношений, но без успеха ... – cheesemacfly

3

Эта проблема кажется уникальной, если: 1) вы используете таблицу объединений с составными ключами, 2) формируете компонент, а 3) таблица соединений - это сущность, которая строится в поле «коллекция» компонента формы. Я видел много людей, имеющих проблемы, но не так много решений, поэтому я думал, что поделюсь с вами.

Я хотел сохранить свой составной первичный ключ, поскольку я хотел убедиться, что в базе данных будет сохраняться только один экземпляр двух внешних ключей.Использование this entity setup в качестве примера

/** @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 с, я не смог бы сохранить OrderItem объект без сначала сохранили объект Order Entity (так как доктрина/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 object with two foreign identities in doctrine). Но это доктрина для вас, со всей ее силой, она обязательно может поставить вас в привязку. Но, к счастью, вам придется делать это только при создании нового объекта, а не редактировании, потому что объект уже находится в базе данных.

Смежные вопросы