Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-2409

Merge operation tries to add new detached entities to indentity map and load them as proxies

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.3.1
    • Fix Version/s: 2.4, 2.3.4
    • Component/s: ORM
    • Security Level: All
    • Labels:
      None

      Description

      class A
          {
             /**
              *  @ORM\ManyToOne(targetEntity= "B"...
              *  @ORM\JoinColumn(name=" ...
              */
              protected $b;
              
              public function getB()
              {
                  return $this->b;
              }
              
              public function setB($b)
              {
                  $this->b = $b;
              }
      }
          
          class B
      	{
             /**
              * As
              *
              * @var \Doctrine\Common\Collections\Collection
              *
              * @ORM\OneToMany(targetEntity="A", mappedBy="B")
              */
      		protected $As;
          }
      	
      	$b = new \B();
      	
      	$a = $em->find('A', 123);
      	
      	$a->setB($b);
      	
      	$em->detach($a);
      	
      	$em->detach($b);
      	
      	$b = $em->merge($b); // notice that $b now is merged
      	
      	$a = $em->merge($a); //  hangs as it creates the proxy for $b and tries to load a though __load even though $b is already managed
      

      Couple of possible issues in the following code from doMerge:

      if ($assoc2['type'] & ClassMetadata::TO_ONE) {
                              $other = $prop->getValue($entity);
                              if ($other === null) {
                                  $prop->setValue($managedCopy, null);
                              } else if ($other instanceof Proxy && !$other->__isInitialized__) {
                                  // do not merge fields marked lazy that have not been fetched.
                                  continue;
                              } else if ( ! $assoc2['isCascadeMerge']) {
                                  if ($this->getEntityState($other, self::STATE_DETACHED) !== self::STATE_MANAGED) {
                                      $targetClass = $this->em->getClassMetadata($assoc2['targetEntity']);
                                      $relatedId = $targetClass->getIdentifierValues($other);
      
                                      if ($targetClass->subClasses) {
                                          $other = $this->em->find($targetClass->name, $relatedId);
                                      } else {
                                          $other = $this->em->getProxyFactory()->getProxy($assoc2['targetEntity'], $relatedId);
                                          $this->registerManaged($other, $relatedId, array());
                                      }
                                  }
                                  $prop->setValue($managedCopy, $other);
                              }
      
           $relatedId = $targetClass->getIdentifierValues($other);
      

      $relatedId is emply as the detached $other was never flushed. It should never be used to add this entity to the identityMap ($this->registerManaged($other, $relatedId, array())

      $other = $this->em->getProxyFactory()->getProxy($assoc2['targetEntity'], $relatedId);
      

      This should never use the proxy factory for new detached entities as they are already merged back ($b). This method seems to not have any means to find managed $b.

      If $b = $em->merge($b); was not called, the method would probably have worked but I think it is not right to rely on that calling or not calling certain methods or their order.

        Activity

          People

          • Assignee:
            Fabio B. Silva
            Reporter:
            Oleg Namaka
          • Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: