Doctrine 2 - ORM
  1. Doctrine 2 - ORM
  2. DDC-992

ManyToMany self referencing association bug with lazy loading

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 2.0
    • Fix Version/s: 2.0.4
    • Component/s: ORM
    • Security Level: All
    • Labels:
      None
    • Environment:
      Doctrine 2.0.0

      Description

      Hi there I encountered a bug. When was trying to get ManyToMany self referencing association via lazy loading.

      Here is my Entity.

      use Doctrine\Common\Collections\ArrayCollection;
      
      /**
       *
       * @Table(name="Roles")
       * @entity(repositoryClass="Users_Model_RoleRepo")
       */
      
      class Users_Model_Entity_Role extends Viscomp_Doctrine_Entity_Abstract
      {
      /**
      	 *  @Id  @Column(name="roleID", type="integer")
      	 *  @GeneratedValue(strategy="AUTO")
      	 *
      	 */
      	protected $roleID;
      
      	/**
      	 * @Column (name="name", type="string", length="45")
      	 *
      	 *
      	 */
      	protected $name;
      
      	/**
      	 * @Column (name="shortName", type="string", length="45")
      	 *
      	 *
      	 */
      	protected $shortName;
      
       	/**
       	 * @ManyToMany (targetEntity="Users_Model_Entity_Role", mappedBy="extends")
        	 */
      	protected $extendedBy;
      
      	/**
      	 * @ManyToMany (targetEntity="Users_Model_Entity_Role", inversedBy="extendedBy")
      	 * @JoinTable (name="RoleRelations",
      	 *      joinColumns={@JoinColumn(name="roleID", referencedColumnName="roleID")},
      	 *      inverseJoinColumns={@JoinColumn(name="extendsRoleID", referencedColumnName="roleID")}
      	 *      )
      	 */
      	protected $extends;
      
      	public function __construct() {
      		$this->extends = new ArrayCollection;
      		$this->extendedBy = new ArrayCollection;
         }
      
      }
      

      When I call

      $test = $this->getEntityManager()->getRepository('Users_Model_Entity_Role')->findOneBy(array('roleID' => 3));
      Doctrine\Common\Util\Debug::dump($test); die;
      

      The SQL that is generated is :

      SELECT t0.roleID AS roleID1, t0.name AS name2, t0.shortName AS shortName3 FROM Roles t0 WHERE t0.roleID = ? array(1) { [0]=>  int(3) } 
      
      SELECT t0.roleID AS roleID1, t0.name AS name2, t0.shortName AS shortName3 FROM Roles t0 INNER JOIN RoleRelations ON t0.roleID = RoleRelations.roleID WHERE RoleRelations.extendsRoleID = ?
      array(1) {
        [0]=>
        int(3)
      }
      SELECT t0.roleID AS roleID1, t0.name AS name2, t0.shortName AS shortName3 FROM Roles t0 INNER JOIN RoleRelations ON t0.roleID = RoleRelations.extendsRoleID WHERE t0.roleID = ?
      array(1) {
        [0]=>
        int(3)
      }
      
      

      In the last SQL query there is a mistake in the where clause it should be RoleRelations.roleID = ? and not t0.roleID = ?. And because of that it is not returning correct result.

        Activity

        Hide
        victor Velkov added a comment -

        The solution that I found is in the class BasicEntityPersister on line 1123 we have

         $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
        

        and i replace it with

        if ($assoc !== null
            && $assoc['targetEntity'] == $assoc['sourceEntity']
            && $assoc['type'] == ClassMetadata::MANY_TO_MANY) {
                $owningAssoc = $assoc['isOwningSide'] ? $assoc : $this->_em->getClassMetadata($assoc['targetEntity'])
                                                                           ->associationMappings[$assoc['mappedBy']];
        	$conditionSql .= $this->_class->getQuotedJoinTableName($owningAssoc, $this->_platform) . '.';
        
        } else {
                 $conditionSql .= $this->_getSQLTableAlias($this->_class->name) . '.';
        }
        

        I am not sure if that is the correct answer but as far as i have tested it doesn't mess up with the normal many to many association via join table.

        Show
        victor Velkov added a comment - The solution that I found is in the class BasicEntityPersister on line 1123 we have $conditionSql .= $ this ->_getSQLTableAlias($ this ->_class->name) . '.'; and i replace it with if ($assoc !== null && $assoc['targetEntity'] == $assoc['sourceEntity'] && $assoc['type'] == ClassMetadata::MANY_TO_MANY) { $owningAssoc = $assoc['isOwningSide'] ? $assoc : $ this ->_em->getClassMetadata($assoc['targetEntity']) ->associationMappings[$assoc['mappedBy']]; $conditionSql .= $ this ->_class->getQuotedJoinTableName($owningAssoc, $ this ->_platform) . '.'; } else { $conditionSql .= $ this ->_getSQLTableAlias($ this ->_class->name) . '.'; } I am not sure if that is the correct answer but as far as i have tested it doesn't mess up with the normal many to many association via join table.
        Hide
        Benjamin Eberlei added a comment -

        There is a simple workaround if you rename the "roleID" from the join table to something else, childRoleID for example. This should work for now. I am looking into a way to fix this issue.

        Show
        Benjamin Eberlei added a comment - There is a simple workaround if you rename the "roleID" from the join table to something else, childRoleID for example. This should work for now. I am looking into a way to fix this issue.
        Hide
        victor Velkov added a comment -

        Ok thanks

        Show
        victor Velkov added a comment - Ok thanks
        Hide
        Benjamin Eberlei added a comment -

        Fixed, merged into 2.0.x branch.

        Show
        Benjamin Eberlei added a comment - Fixed, merged into 2.0.x branch.

          People

          • Assignee:
            Benjamin Eberlei
            Reporter:
            victor Velkov
          • Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: