Doctrine requires mappedBy in a OneToMany unidirectional association
A OneToMany
has to be bi-directional and is always the inverse side of a relationship and if you define the inverse side you need to point at the owning side of the relationship with a mappedBy
attribute. The owning side is ManyToOne
. In your case this would look like this:
In User
your association has a mappedBy="user"
attribute and points to the owning side Address
:
/** ONE-TO-MANY BIDIRECTIONAL, INVERSE SIDE
* @var Collection
* @ORM\OneToMany(targetEntity="Address", mappedBy="user")
*/
protected $addresses;
In Address
your association has a inversedBy="addresses"
attribute and points to the inverse side User
:
/** MANY-TO-ONE BIDIRECTIONAL, OWNING SIDE
* @var User
* @ORM\ManyToOne(targetEntity="User", inversedBy="addresses")
* @ORM\JoinColumn(name="user_id", referencedColumnName="id")
*/
protected $user;
The advantage of this solution is that you can find which user owns the Address
by doing: $address->getUser();
and that you skip adding an additional join table to your database.
If you want the relationship to be uni-directional you can do as you did in your update; define a ManyToMany
relationship with a join table and add a unique constraint on the address_id
column.
/**
* @ORM\ManyToMany(targetEntity="Address")
* @ORM\JoinTable(name="user_address",
* joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")},
* inverseJoinColumns={@ORM\JoinColumn(name="address_id", referencedColumnName="id", unique=true)}
* )
*/
The disadvantage of this solution is that you cannot find out which User
owns the address from the Address
resource (the Address
is not aware of the User
). Such example can also be found here in the Doctrine documentation chapter 5.6. One-To-Many, Unidirectional with Join Table.
Related videos on Youtube
Comments
-
mevqz over 1 year
When I try to make a OneToMany unidirectional association between this two entities i get this error when i try to update the database schema:
$ app/console doctrine:schema:update --dump-sql
[Doctrine\ORM\Mapping\MappingException]
OneToMany mapping on field 'address' requires the 'mappedBy' attribute./** * User * * @ORM\Table() * @ORM\Entity */ class User { /** * @var integer * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; /** * @ORM\OneToMany(targetEntity="Address") * @ORM\JoinTable(name="users_address", * joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}, * inverseJoinColumns={@ORM\JoinColumn(name="address_id", referencedColumnName="id", unique=true)} * ) */ private $address; //... } /** * Address * * @ORM\Table() * @ORM\Entity */ class Address { /** * @var integer * * @ORM\Column(name="id", type="integer") * @ORM\Id * @ORM\GeneratedValue(strategy="AUTO") */ private $id; // ... }
Why is "mappedBy" required if the association is unidirectional? Thanks in advance.
UPDATE: just as mentioned in the comment by @tchap an unidirectional OneToMany can be mapped with a @ManyToMany and a unique constraint on one of the join columns to enforce the onetomany cardinality. Just as the documentation says, but it was a bit confusing for me because there is already a @OneToMay annotation. So I just have to change the above code to this (by only changing the @OneToMany to @ManyToMany):
/** * @ORM\ManyToMany(targetEntity="Address") * @ORM\JoinTable(name="users_address", * joinColumns={@ORM\JoinColumn(name="user_id", referencedColumnName="id")}, * inverseJoinColumns={@ORM\JoinColumn(name="address_id", referencedColumnName="id", unique=true)} * ) */ private $address;
-
Remi M over 7 years@tchap to me A JoinTable for a OneToMany association makes sense if the entities on the Many side can be owned by different type of entities. In this case the typical foreign key on this side won't be enough to distinguish the owner unless you use UUID for all your entities.
-
-
mevqz over 8 yearsThanks. You got a typo for the owning side (it should be ManyToOne instead OneToMany), but this is the correct answer.
-
Wilt over 8 years@mevqz oops, fixed it :P
-
Remi M over 7 years@Wilt In your last example, I suppose you talk about the User entity since the target entity is Address. There's a typo, the address_id with the unique =true property is in the inverseJoinColumns, not the joinColumns :)
-
Wilt over 7 years@Azuli42 Very true, thanks! I fixed it and added a link to the documentation. I copied the annotation from the question, so the same mistake was made there.
-
Wilt over 7 years@Azuli42 I edited the question and fixed it there too.