Search code examples
symfonydoctrine-orm

Join columns by referencedColumnName that is not primary key - id


I am rookie in Symfony Doctrine and need some help with Join entities.

Normally Column are joins by primary key ID

    /**
     * User
     *
     * @ORM\Table(name="users")
     * @ORM\Entity(repositoryClass="MainBundle\Repository\UserRepository")
     * UniqueEntity("email", message="Account with email already exists.")
     */
    class User implements AdvancedUserInterface, \Serializable
    {
    /**
         * @var \MainBundle\Entity\PersonDetails
         *
         * @ORM\ManyToOne(targetEntity="MainBundle\Entity\Person")
         * @ORM\JoinColumns({
         *  @ORM\JoinColumn(name="person_details_id", referencedColumnName="id", nullable=true)
         * })
         */
    private $personDetails = null;

This is ok.

But problem is that I want to Join two columns in Relation OneToOne by id field in User Entity


    /**
     * User
     *
     * @ORM\Table(name="users")
     * @ORM\Entity(repositoryClass="MainBundle\Repository\UserRepository")
     * UniqueEntity("email", message="Account with email already exists.")
     */
    class User implements AdvancedUserInterface, \Serializable
    {
    /**
         * @var \MainBundle\Entity\PersonDetails
         *
         * @ORM\ManyToOne(targetEntity="MainBundle\Entity\Person")
         * @ORM\JoinColumn(name="id", referencedColumnName="user_id", nullable=true)
             * })
             */
        private $personDetails = null;

When I try to join columns on this way I get error

Missing value for primary key id on MainBundle\Entity\PersonDetails

Is it possible to index other field than id or what I trying to do is impossible?

Thanks guys.


Solution

  • You have mixed up the column-name and the field-name that shall be referenced in your @JoinColumn declaration.

    @JoinColumn(name="id", referencedColumnName="user_id")
    

    This way Doctrine looks for a field/property named user_id on your User entity. I guess you want the column in the join-table to be named user_id and the entries being id's of the User entity.

    UserDetail

    /**
     * @ORM\Entity
     */
    class UserDetail
    {
        /**
         * @ORM\ManyToOne(
         *   targetEntity="User",
         *   inversedBy="details"
         * )
         * @ORM\JoinColumn(
         *   name="user_id",
         *   referencedColumnName="id"
         * )
         */
        protected $user;
    
        public function setUser(User $user)
        { 
            $this->user = $user;
    
            return $this;
        }
    
        /** @ORM\Column() */
        protected $key;
    
        /** @ORM\Column() */
        protected $value;
    
        public function __construct($key, $value)
        {
           $this->key = $key;
           $this->value = $value;
        }
    

    User

    class User
    {
        /**
         * @ORM\Id()
         * @ORM\Column(type="integer")
         */
        protected $id;
    
        /** 
         * @ORM\OneToMany(
         *   targetEntity="UserDetail",
         *   mappedBy="user", 
         *   cascade={
         *     "persist",
         *     "remove",
         *     "merge"
         *   },
         *   orphanRemoval=true
         * )
         */
        protected $details;
    
        public function __construct()
        {
            $this->details = new ArrayCollection();
        }
    
        public function addDetail(UserDetail $detail)
        {
            $detail->setUser($this);
            $this->details->add($detail);
    
            return $this;
        }
    

    Now if you add a detail to your User like this and persist/flush afterwards:

    $user->addDetail(new UserDetail('Height', '173cm'));
    

    This will result in a join-colum in the user_detail table that looks like this:

    | key           | value     | user_id |
    |---------------|-----------|---------|
    | Height        | 173cm     | 1       |