mvorisek
mvorisek

Reputation: 3418

Doctrine and unique entities in many-to-many, possible?

I have two classes A and B in many to many relation.

the class A looks like this:

/** @ORM\Entity **/
class A {
    /** @ORM\ManyToMany(targetEntity="B", cascade={"all"}) **/
    public $x;
}

the doctrine will create a glue A_B table with columns AId and BId.

Is it possible to make the BId column unique, ie. there will no B entity in for two A entities?

Upvotes: 0

Views: 1295

Answers (2)

Jannes Botis
Jannes Botis

Reputation: 11242

So you want:

One B entity to relate to only one A entity, but one A entity can relate to many different B entities.

This can be done by making the relation to OneToMany from A to B:

class A { 
      /**     
       * @ORM\OneToMany(targetEntity="B", mappedBy="a", cascade={"all"}) 
      **/ 
      public $x;
  }

and in entity B:

class B { 
      /**     
       * @ORM\ManyToOne(targetEntity="A", inversedBy="x") 
      **/ 
      public $a;
  }

This way, each B entity will be "unique", as a foreigh key relation to A 's id is created on B entity 's table.

Do not be confused by the name "OneToMany", 2 B entities cannot be shared between 2 A entities, that would be a ManyToMany. Each B entity will belong to only one A entity.

Upvotes: 0

Alan T.
Alan T.

Reputation: 1430

What you are describing is a unidirectional One-to-Many association. To set it up, you need to use the JoinTable annotation to enforce the one-to-many cardinality as explained in this section of the documentation.

With your A and B entities, it would be something like:

/** @ORM\Entity **/
class A 
{
    /* ... other attributes ... */

    /**
     * @ORM\ManyToMany(targetEntity="B")
     * @ORM\JoinTable(inverseJoinColumns={@ORM\JoinColumn(unique=true, onDelete="CASCADE")})
     */    
    public $bs;
}

I just kept the unique option that applies on the b_id column as other options such as column and table names are automatically generated for you anyway. I added onDelete="CASCADE" as it should be the default behaviour you would want in an association table.

With this association, doctrine will output the following schema:

CREATE TABLE a_b (a_id INT NOT NULL, b_id INT NOT NULL, INDEX IDX_28CB39EA3BDE5358 (a_id), UNIQUE INDEX UNIQ_28CB39EA296BFCB6 (b_id), PRIMARY KEY(a_id, b_id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
ALTER TABLE a_b ADD CONSTRAINT FK_28CB39EA3BDE5358 FOREIGN KEY (a_id) REFERENCES a (id) ON DELETE CASCADE;
ALTER TABLE a_b ADD CONSTRAINT FK_28CB39EA296BFCB6 FOREIGN KEY (b_id) REFERENCES b (id) ON DELETE CASCADE;

On a side note, if it does not matter that B owns the association, simply having a bidirectional OneToMany association owned by B and inversed in A would do as it would add a foreign key on B's table referring to A, thus enforcing the right cardinality as well.

Upvotes: 2

Related Questions