'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.
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 |