Reputation: 2254
I'm using Doctrine 2.1 where Identity through foreign Entities is supported (Foreign Keys as Identifiers).
Is it possible to identity through foreign Entities with a bidirectional relationship? I'm trying but I'm getting the following error when I load my data fixtures:
[PDOException]
SQLSTATE[23000]: Integrity constraint violation: 1452 Cannot add or update a child row: a foreign key constraint fails (
table
.user
, CONSTRAINTFK_187DDE86BF396750
FOREIGN KEY (id
) REFERENCESaddress
(user_id
))
Here are my entities:
/**
* @Entity
*/
class User
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @OneToOne(targetEntity="Address") */
private $address;
}
/**
* @Entity
*/
class Address
{
/** @Id @OneToOne(targetEntity="User") */
private $user;
}
If I remove the reference from User to Address the error disappears!
I would like to be able to do the following:
$address = $user->getAddress();
..but it seems I will have to do:
$address = $entityManager->find('Address', $user->getId());
Is that right? Is there a way to do this?
Update 1:
I would like to be able to set the relationship from either side (bidirectional) but this does not seem possible.
To be honest I'm not sure what the point of the inverse side of the relationship is because "Changes made only to the inverse side of an association are ignored".
Taken from the docs here: http://docs.doctrine-project.org/projects/doctrine-orm/en/2.1/reference/association-mapping.html#owning-side-and-inverse-side
What is the point?
From an Application perspective it seems to make more sense to do:
$user->setAddress($address);
rather than:
$address->setUser($user);
However the first isn't possible possible because:
User
side has to be the inverse side so $user->setAddress($address);
will be ignored anyway!!Will someone explain this please :)
Matthew
Upvotes: 0
Views: 667
Reputation: 31
Your problem is not related to "Foreign Keys as Identifiers", but to owning-side of a relation :
In Doctrine, a relation may be bidirectional, but in this case the relation must have an "onwing-side". That means :
on your "entities part" : both your entities have an attribute referencing each other. In your case you have $address in User and $user in Address, and you can use $user->getAddress() and $address->getUser()
on your "sql part" : only one table, the owning-side, have an attribute referencing the other table.
You can inform Doctrin what is the owning side by using "mappedBy" on the non-owning side. In your situation, with Foreign Key as Identifiers, you have not the choice : the owning-side is the one with Foreign Key. So, test this :
/**
* @Entity
*/
class User
{
/** @Id @Column(type="integer") @GeneratedValue */
private $id;
/** @OneToOne(targetEntity="Address", mappedBy="user") */
private $address;
}
/**
* @Entity
*/
class Address
{
/** @Id @OneToOne(targetEntity="User", inversedBy="address")) */
private $user;
}
Another important point : In a bidirectional relation, Doctrine can't automaticaly update the other side when you set the non-owning side. So you have to do it manualy. For not having do think about this each time you create new users and addresses, you can automate the process in your setter :
// in class User :
public function setAddress($address) {
$address->setUser($this); // <= here it is !!!
$this->address = $address;
return $this;
}
// in class Address :
public function setUser($user) {
$this->user = $user;
return $this;
}
Now, you can set address like you want, without bothering about this owning-side-things :
$address = new Addresse();
$address->set...
$user->setAddress($address);
Upvotes: 1
Reputation: 1702
Do you have getter for the address field defined in your User entity?
public function getAddress()
{
return $this->address;
}
Remember that the doctrine returns always collection.
Upvotes: 0