Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-3083

Persist/Flush silently fails when CTI is applied on an existing table

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 2.4.2
    • Fix Version/s: None
    • Component/s: ORM
    • Security Level: All
    • Labels:
      None

      Description

      Given an existing table (= parent table) the integration of a new parent-child relationship with Class Table Inheritance (CTI) leads to a update problem.

      First of all a child table is created with a foreign key to the parent table. Next, the discriminator column is added to the parent table. The discriminator map will be auto-generated.

      The problem arises when trying to perform persist() and flush() on a child entity. Initially the child table is logically empty. However, the UnitOfWork triggers updateTable() which will fail since there is nothing to update. Instead, an upsert should be performed.

      Another sneaky thing is that the repository will return the child class with the updated data after calling flush() on the same request. On the next request the child class is returned with the data loaded from the persister. Of course, the updated data is missing.

        Activity

        Hide
        Marco Pivetta added a comment -

        Frank Liepert do I understand this correctly if I say that you are trying to (pseudo) upcast an entity to a more specific subtype? That is unsupported by the ORM. Could you make just an example snippet of what you described in the issue?

        Show
        Marco Pivetta added a comment - Frank Liepert do I understand this correctly if I say that you are trying to (pseudo) upcast an entity to a more specific subtype? That is unsupported by the ORM. Could you make just an example snippet of what you described in the issue?
        Hide
        Frank Liepert added a comment -

        Marco Pivetta: You have understood really well. If you say that's not supported by the ORM then this is the answer. Still I think that upsert could solve solve the "problem" and I know that there are/have been discussions about upsert.

        Right now I will continue to manually insert the missing rows in the child table. After this necessary step the ORM works as expected.

        Nevertheless the real bug is that after persist() and flush() the entity manager returns the child object with the "persisted" data of the child table although there are in fact no rows in the child table.

        $parentRepository = $em->getRepository('Parent');
        
        $child = $parentRepository ->find(1);
        $child->setChildPropertyA('foo');
        
        $em->persist($child);
        $em->flush();
        
        $child = $parentRepository ->find(1);
        var_dump($child->getChildPropertyA());
        // string(3) "foo"
        
        // But: There is no 'foo' in the child table!
        
        
        /** 
         * NEW REQUEST
         */
        
        $parentRepository = $em->getRepository('Parent');
        
        $child = $parentRepository ->find(1);
        var_dump($child->getChildPropertyA());
        // NULL
        
        
        Show
        Frank Liepert added a comment - Marco Pivetta: You have understood really well. If you say that's not supported by the ORM then this is the answer. Still I think that upsert could solve solve the "problem" and I know that there are/have been discussions about upsert. Right now I will continue to manually insert the missing rows in the child table. After this necessary step the ORM works as expected. Nevertheless the real bug is that after persist() and flush() the entity manager returns the child object with the "persisted" data of the child table although there are in fact no rows in the child table. $parentRepository = $em->getRepository('Parent'); $child = $parentRepository ->find(1); $child->setChildPropertyA('foo'); $em->persist($child); $em->flush(); $child = $parentRepository ->find(1); var_dump($child->getChildPropertyA()); // string(3) "foo" // But: There is no 'foo' in the child table! /** * NEW REQUEST */ $parentRepository = $em->getRepository('Parent'); $child = $parentRepository ->find(1); var_dump($child->getChildPropertyA()); // NULL
        Hide
        Marco Pivetta added a comment -

        Frank Liepert why are $child in the first request and $child in the second request different here? Are you manually changing the data at SQL level?

        Show
        Marco Pivetta added a comment - Frank Liepert why are $child in the first request and $child in the second request different here? Are you manually changing the data at SQL level?
        Hide
        Frank Liepert added a comment -

        Marco Pivetta as I have explained the persist() and flush() in the first request trigger an UPDATE command (Because there is already a row in the parent table?). Given that the child table was manually created before there are no rows on that table at that time and therefore nothing can be updated. Nevertheless the ORM triggers no error and $child looks like having been persisted. In the second request you'll notice that there haven't been persisted any of the data belonging to the child table.

        Show
        Frank Liepert added a comment - Marco Pivetta as I have explained the persist() and flush() in the first request trigger an UPDATE command (Because there is already a row in the parent table?). Given that the child table was manually created before there are no rows on that table at that time and therefore nothing can be updated. Nevertheless the ORM triggers no error and $child looks like having been persisted. In the second request you'll notice that there haven't been persisted any of the data belonging to the child table.

          People

          • Assignee:
            Benjamin Eberlei
            Reporter:
            Frank Liepert
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated: