Search code examples
symfonydoctrine-ormsymfony-2.2

Composite key and form


I have the following associations in my database (simplified version):

db schema

This is a Many-To-Many association but with an attribute on the joining table, so I have to use One-To-Many/Many-To-One associations.

I have a form where I can add as many relations as I want to one order item and create it at the same time (mainly inspired by the How to Embed a Collection of Forms tutorial from the documentation.

When I post the form, I get the following error:

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.

I understand this error because Doctrine tries to persist the Relation object(s) related to the order since I have the cascade={"persist"} option on the OneToMany relation. But how can I avoid this behavior?

I have tried to remove cascade={"persist"} and manually persist the entity, but I get the same error (because I need to flush() order to get the ID and when I do so, I have the same error message).
I also tried to detach() the Relation objects before the flush() but with no luck.


Solution

  • I ended up creating a separated primary key on my Relation table (instead of having the composite one).
    It looks like it is a dirty fix, and I am sure there is a better way to handle this situation but it works for now.

    Here is my Relations entity:

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

    I then added the cascade={"persist"} option on the OneToMany relation with Order:

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

    Et voilà!