Choose owning side in OneToOne relation

2 minute read

Many times I’ve come got to a situation where I have a unusual high query count. When I inspect the queries in the Symfony profiler I can see that Doctrine is fetching objects I have not requested. To give you a clear image of the problem I’ll show an example of the database mapping.

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

private $id;


/**
* @ORM\OneToOne(targetEntity="Resume", mappedBy="user")
*/

private $resume;
}


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

private $id;


/**
* @ORM\OneToOne(targetEntity="User", inversedBy="resume")
*/

private $user;
}

This will create SQL like this:

CREATE TABLE Resume (id INT AUTO_INCREMENT NOT NULL, user_id INT DEFAULT NULL, UNIQUE INDEX UNIQ_6602EC1AA76ED395 (user_id), PRIMARY KEY(id))
CREATE TABLE User (id INT AUTO_INCREMENT NOT NULL, PRIMARY KEY(id))
ALTER TABLE Resume ADD CONSTRAINT FK_6602EC1AA76ED395 FOREIGN KEY (user_id) REFERENCES User (id)

The relation information is on the Resume table because the Resume entity is on the owing side.

Fetching the relation eagerly

As a consequence of Resume being on the owning side of the OneToOne relation it will always be fetched eagerly. You can not fetch it as lazy (default for other relations) or extra lazy. This means that every time you fetch the user entity Doctrine will make a second query to fetch the Resume object. This could be the desired behavior with some relations but not in this case. It is reasonable to think that most of the the you may use the User object without the Resume.

Owning Side and Inverse Side

There is a few things to know about the owning side and the inverse side.

  • The owning side has the inversedBy attribute.
  • The inverse side has the mappedBy attribute.
  • Doctrine will only check the owning side of an association for changes.
  • The owning side of a OneToOne association is the entity with the table containing the foreign key

Source: Doctrine docs

The fix

The fix for this problem is simple. You just change the owning side and inverse side. Make the User entity the owning entity. It makes sense to eagerly fetch the User when you fetch a Resume, right?

So, the rule of thumb here is:

The entity that owns the relation does not need the relation. The inverse side is depended on the relation and will fetch it's owner.

 

Leave a Comment