'Doctrine 2 mapping referencing unique key

Basic question:

Is it possible to map an association using Doctrine referencing not a primary but only a unique key?

Extended Version:

I have an Entity (Participation) which may reference 2 other entities (DropoutCause and DischargeType). Depending on this combination some other attributes are implied, based on another (4th) table (DropoutScenario) in database. Because either of both referenced entities may be null I couldn't declare them as primary but only unique key in the 4th table.

The problem is I only get an error when I try to map this with Doctrine:

Missing value for primary key id on Application\Entity\Trainings\DropoutScenario

Am I doing something wrong, or is this simply not possible with Doctrine? If not, is there any better solution how I could do this?

I've been searching for quite a long time now and dug the Doctrine documentation but I simply couldn't find anything on this...

Stripped code samples of my mappings are below.

Participation:

<?php

namespace Application\Entity\Trainings;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\MappedSuperclass
 */
abstract class Participation {

    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Application\Entity\DropoutCause")
     * @ORM\JoinColumn(name="dropout_cause_id", referencedColumnName="id"))
     */
    protected $dropoutCause;

    /**
     * @ORM\ManyToOne(targetEntity="Application\Entity\DischargeType")
     * @ORM\JoinColumn(name="discharge_id", referencedColumnName="id"))
     */
    protected $dischargeType;

    /**
     * @ORM\ManyToOne(targetEntity="DropoutScenario")
     * @ORM\JoinColumns({
     * @ORM\JoinColumn(name="discharge_id", referencedColumnName="discharge_id"),
     * @ORM\JoinColumn(name="dropout_cause_id", referencedColumnName="dropout_cause_id")
     * })
     */
    private $scenario;

DropoutScenario:

<?php

namespace Application\Entity\Trainings;

use Doctrine\ORM\Mapping as ORM;

/**
 * @ORM\Entity
 * @ORM\Table(name="training_dropout_scenarios")
 */
class DropoutScenario {

    /**
     * @var int
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Application\Entity\DropoutCause")
     * @ORM\JoinColumn(name="dropout_cause_id", referencedColumnName="id"))
     */
    protected $dropoutCause;

    /**
     * @ORM\ManyToOne(targetEntity="Application\Entity\DischargeType")
     * @ORM\JoinColumn(name="discharge_id", referencedColumnName="id"))
     */
    protected $dischargeType;

    /** @ORM\Column(type="integer", name="dropout_cause_id") */
    protected $dropoutCauseId;

    /** @ORM\Column(type="integer", name="discharge_id") */
    protected $dischargeTypeId;


Solution 1:[1]

Since I did not get any answer yet I did another research today and I found the answer to my own question through the Doctrine mailing lists forum. Seems like I just searched for the wrong keywords...

Doctrine 2 unfortunately does not support it. What a pity! :(

From the Doctrine documentation: https://www.doctrine-project.org/projects/doctrine-orm/en/2.6/reference/limitations-and-known-issues.html#join-columns-with-non-primary-keys

It is not possible to use join columns pointing to non-primary keys. Doctrine will think these are the primary keys and create lazy-loading proxies with the data, which can lead to unexpected results. Doctrine can for performance reasons not validate the correctness of this settings at runtime but only through the Validate Schema command.

Similar question: Is it possible to reference a column other than 'id' for a JoinColumn?

Solution 2:[2]

Just like following references, Doctrine does not support this type of mapping

http://www.doctrine-project.org/jira/browse/DDC-1269

http://www.doctrine-project.org/jira/browse/DDC-1114

I think it will be helps to you.

Solution 3:[3]

My two cents for this very old question.

Its true that Doctrine 2 does not support mapping relation to a non primary key mapped column, however its possible to simulate it.

OneToOne Mapping example

Example in yml format:

### UserEntity.dcm.yml
UserEntity:
type: entity
repositoryClass: UserRepository
table: User
id:
  id:
    type: integer
      nullable: false
      length: 9
      options:
        unsigned: true
      id: true
      column: id
      generator:
        strategy: AUTO
  fields:
    status:
      type: integer
      nullable: false
      length: 2
      options:
        fixed: false
      column: status
    dateOfBirth:
      type: datetime
      nullable: true
      options:
        fixed: false
      column: date_of_birth
    createdAt:
      type: datetime
      nullable: true
      options:
        fixed: false
      column: created_at
  userAvatar:
    targetEntity: AvatarEntity
    joinColumn:
      name: id
      referencedColumnName: user_id
  lifecycleCallbacks: {  }


### AvatarEntity.dcm.yml
User/AvatarEntity:
  type: entity
  repositoryClass: AvatarRepository
  table: Avatar
  id:
    userId:
      type: integer
      nullable: false
      length: 9
      options:
        unsigned: true
      id: true
      column: user_id
      generator:
        strategy: NONE
  fields:
    imageName:
      type: string
      nullable: false
      length: 255
      options:
        fixed: false
      column: image_name
  lifecycleCallbacks: {  }

With this yml we now can get the Avatar entry through user_id column like primary key from User. With the id definition poiting to this column on AvatarEntity.dcm.yml and the oneToOne relation on UserEntity.dcm.yml we do the trick and the resultant SQL will be correct like we want.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Thomas Landauer
Solution 2 Glorfindel
Solution 3 Marcos Regis Santos