Skip to content

Loading…

DDC-2421: Many-To-Many relation creation failed when using non PK entity field #3135

Closed
doctrinebot opened this Issue · 5 comments

2 participants

@doctrinebot

Jira issue originally created by user jedi_bc:

Given these entities :

/****
 * Class Domain
 *
 * @ORM\Entity
 * @ORM\Table(name="profils_domains")
 */
class Domain
{
    /****
     * @var string
     *
     * @ORM\Id
     * @ORM\Column(type="string", length=22, nullable=false)
     */
    protected $name = '';
}
/****
 * Class Web
 *
 * @ORM\Entity
 * @ORM\Table(name="profils_webs",
 *          uniqueConstraints={@ORM\UniqueConstraint(name="web_unique",columns={"name", "domain"})}
 * )
 */
class Web
{
    /****
     * @var integer
     *
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer", nullable=false)
     */
    protected $id;

    /****
     * @var string
     *
     * @ORM\Column(type="string", length=22, nullable=false)
     */
    protected $name = '';

    /****
     * @var Domain
     *
     * @ORM\ManyToOne(targetEntity="Domain", fetch="LAZY")
     * @ORM\JoinColumn(name="domain", referencedColumnName="name", nullable=false, onDelete="CASCADE")
     */
    protected $domain;
}
/****
 * Class WebsGroup
 *
 * @ORM\Entity
 * @ORM\Table(name="profils_websgroups",
 *          uniqueConstraints={@ORM\UniqueConstraint(name="websgroup_unique",columns={"name", "domain"})}
 * )
 */
class WebsGroup
{
    /****
     * @var integer
     *
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer", nullable=false)
     */
    protected $id;

    /****
     * @var string
     *
     * @ORM\Column(type="string", length=22, nullable=false)
     */
    protected $name = '';

    /****
     * @var Domain
     *
     * @ORM\ManyToOne(targetEntity="Domain", fetch="LAZY")
     * @ORM\JoinColumn(name="domain", referencedColumnName="name", nullable=false, onDelete="CASCADE")
     */
    protected $domain;

    /****
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Web", indexBy="id", fetch="EXTRA_LAZY")
     * @ORM\JoinTable(name="profils*websgroups*webs",
     *      joinColumns={
     * @ORM\JoinColumn(name="websgroup_id", referencedColumnName="id", onDelete="CASCADE"),
     * @ORM\JoinColumn(name="domain", referencedColumnName="domain", onDelete="CASCADE")
     *          },
     *      inverseJoinColumns={
     * @ORM\JoinColumn(name="web_id", referencedColumnName="id", onDelete="CASCADE"),
     * @ORM\JoinColumn(name="domain", referencedColumnName="domain", onDelete="CASCADE")
     *          }
     *      )
     */
    protected $webs;
}

I've got a domain, some web sites per domain and websgroups which group web sites. I want to be sure in my database that a web group from a domain D can contain only web sites from the very same domain but when calling the console tool for creating my schema it raise :

[Doctrine\ORM\ORMException]                                                                                                                                      
  Column name `domain` referenced for relation from Entity\WebsGroup towards Entity\Web does not exist. 

It's because domain is already an association to an entity which and is not part of the primary key.

I've quick fixed getDefiningClass from Doctrine\ORM\Tools\SchemaTool to make it work but i really don't know if it's the proper way :

    private function getDefiningClass($class, $referencedColumnName)
    {
        $referencedFieldName = $class->getFieldName($referencedColumnName);

        if ($class->hasField($referencedFieldName)) {
            return array($class, $referencedFieldName);
        } else if (in_array($referencedColumnName, $class->getIdentifierColumnNames())) {
            // it seems to be an entity as foreign key
            foreach ($class->getIdentifierFieldNames() as $fieldName) {
                if ($class->hasAssociation($fieldName) && $class->getSingleAssociationJoinColumnName($fieldName) == $referencedColumnName) {
                    return $this->getDefiningClass(
                        $this->em->getClassMetadata($class->associationMappings[$fieldName]['targetEntity']),
                        $class->getSingleAssociationReferencedJoinColumnName($fieldName)
                    );
                }
            }
        } else if (in_array($referencedColumnName, $class->getAssociationNames())) {
            return $this->getDefiningClass(
                $this->em->getClassMetadata($class->associationMappings[$referencedColumnName]['targetEntity']),
                $class->getSingleAssociationReferencedJoinColumnName($referencedColumnName)
            );
        }

        return null;
    }
@doctrinebot

Comment created by @FabioBatSilva:

[~jedi_bc] Except for some CS this fix seems good.

If you have time you can send as pull request

@doctrinebot

Comment created by jedi_bc:

I've start making a PR and a test case but it is linked to http://www.doctrine-project.org/jira/browse/[DDC-2413](http://www.doctrine-project.org/jira/browse/DDC-2413)
I'm looking in making a proper fix to DDC-2413 first.

@doctrinebot

Comment created by @beberlei:

You cannot use a reference column that is not a primary key. Doctrine does not support this.

@doctrinebot

Issue was closed with resolution "Invalid"

@doctrinebot

Comment created by bavo:

I stumbled on this issue when experiencing a similar bug.
There is something seriously wrong with the referencedColumn in a ManyToMany relationship.
When you use a PK as 'id' and set your referenced column to 'id' everything is fine.
But when you use 'productId' as PK and reference it properly creation fails because "column 'id' doens't exists in table", which is very strange. After introducing a bogus column 'id' to the entity, but still referencing 'productId' a linking table is created but it has FK's to 'id' not to productId. When changing the referenced column to 'bogus' the creation also fails because: "column 'bogus' doesn't exists in table".

To me doctrine checks the the referencedColumn for existence but after that just creates everything assuming the default PK 'id'.

@beberlei beberlei was assigned by doctrinebot
@doctrinebot doctrinebot closed this
@doctrinebot doctrinebot added the Bug label
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.