Tesmen
Tesmen

Reputation: 589

Doctrine2 relation for non Id column

I'm building a simple web-service using Symfony 3, Doctrine 2.5 and stuck at ORM relations described below in simplified structure.

I have an Action entity containing many actions with ManyToOne relation...

class Action
{
/**
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var integer
 *
 * @ORM\ManyToOne(targetEntity="\AppBundle\Entity\Status")
 * @ORM\JoinColumn(referencedColumnName="code", nullable=false)
 */
private $status;

and the Status Entity with a few statuses.

class Status
{
/**
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 *
 * @ORM\Column(type="integer", unique=true)
 */
private $code;

I cannot get proper way to set referencedColumnName="code" column (not 'Id' as usual) for Action entity.

Configured this way repo throws wxception at persist moment with "Notice: Undefined index: code";

I guess that it is mappedBy or inversedBy annotation parameter... but can't figure out "how".

Upvotes: 2

Views: 4526

Answers (2)

Just thought I'd add you can still use the non-primary keys as many to many, by using the entity itself as the join table. This will work but you still need to set your relationship keys correctly.

Example:

/**
 * @ORM\Entity
 */
class Car {
  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="bigint", nullable=false)
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="IDENTITY")
   */
  protected $id;

  /**
   * @ORM\Column(name="registration_code", type="text", length=128, nullable=false)
   * @var string
   */
  public $registrationCode;

  /**
   * @var \Doctrine\Common\Collections\Collection
   * @ORM\ManyToMany(targetEntity="Registration", mappedBy="Cars")
   * @ORM\JoinTable(name="car",
   *  joinColumns={@ORM\JoinColumn(name="id", referencedColumnName="id")},
   *  inverseJoinColumns={@ORM\JoinColumn(name="registration_code", referencedColumnName="registration_code")}
   * )
   */
  public $Registrations;

  public function __construct() {
    $this->Cars = new ArrayCollection();
  }
}

/**
 * @ORM\Entity
 */
class Registration {
  /**
   * @var integer
   *
   * @ORM\Column(name="id", type="bigint", nullable=false)
   * @ORM\Id
   * @ORM\GeneratedValue(strategy="IDENTITY")
   */
  protected $id;

  /**
   * @ORM\Column(name="registration_code", type="text", length=128, nullable=false)
   * @var string
   */
  public $registrationCode;

  /**
   * @var ArrayCollection
   * @ORM\ManyToMany(targetEntity="Car", mappedBy="Registrations")
   * @ORM\JoinTable(name="car",
   *   joinColumns={@ORM\JoinColumn(name="registration_code", referencedColumnName="registration_code")},
   *   inverseJoinColumns={@ORM\JoinColumn(name="id", referencedColumnName="id")}
   * )
   */
  public $Cars;

  public function __construct() {
    $this->Cars = new ArrayCollection();
  }
 }

The upside is that it works fine as a workaround.

Keep in mind a few things:

  • it's a collection not a single instance;
  • column has to be managed manually on your end;
  • you must set up constraints correctly (indexes, keys, etc);
  • check your queries still perform!

Upvotes: 2

e1da
e1da

Reputation: 635

Unfortunately it's not supported in Doctrine (reference).

You may edit your Status entity like this (ensure that code is set before persist):

class Status
{

    /**
     * @ORM\Column(name="code", type="integer", unique=true)
     * @ORM\Id
     */
    private $code;

}

If autoincremented field is your requirement you can take a look on this answer for possible solutions.

Upvotes: 3

Related Questions