NOTE: Topic is lengthy but detailed and may come in handy if you use Doctrine2 and oneToOne relationships.
Recently I came across a problem in Doctrine:
I created User and UserData objects with oneToOne bidirectional relationship:
User: ... oneToOne: userdata: targetEntity: UserData mappedBy: user UserData: ... oneToOne: user: targetEntity: User inversedBy: userdata
So UserData was the owning side with user_id column in it:
user: id, ... userdata: id, user_id, ...
This created a problem, where every time you fetch a User object (Single user, collection of user or collection of other object with user joined on it) Doctrine would lazy load a UserObject for each User.
Issue described here:
Proposed solution described here:
So there are 3 ways around this:
I decided to go with #3. So my schema relationship now looks like this:
User: ... oneToOne: userdata: targetEntity: UserData inversedBy: user UserData: ... oneToOne: user: targetEntity: User mappedBy: userdata
This means that my tables now look like this:
user: id, userdata_id, ... userdata: id, ...
I decided that instead of having Userdata.id autoincremented, I'll set it manually and match it with user.id. This means that UserData.id will always match user.id.
Question Can I use user.id (a primary autoincremented key) as joinColum instead of userdata_id since they will always have the same value? Do you see any potential issues with this way of doing things?
Any other tips or opinions about this issue is greatly welcomed and appreciated.
The owning side of the relation tracked by Hibernate is the side of the relation that owns the foreign key in the database.
mappedBy tells Hibernate how to create instances of your entities and load the data into them. It should refer to the field name in the class that you are annotating, PersonDetail in this instance, where the relationship is defined.
The mappedBy attribute characterizes a bidirectional association and must be set on the parent-side. In other words, for a bidirectional @OneToMany association, set mappedBy to @OneToMany on the parent-side and add @ManyToOne on the child-side referenced by mappedBy .
Overview. JPA Relationships can be either unidirectional or bidirectional. This simply means we can model them as an attribute on exactly one of the associated entities or both. Defining the direction of the relationship between entities has no impact on the database mapping.
You could also force partial objects, to get rid off lazy-loading:
use Doctrine\ORM\Query; //... $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true);
This is a known issue for OneToOne associations. There is a github discussion about this that is worth reading. A solution (pull request) was proposed and rejected.
Your question suggests the same solution proposed by the contributors to Doctrine: change the owning side of the relationship.
I had a similar problem with an entity called Version
that had a OneToOne
bidirectional relationship with Settings
. Every time I queried Version
(say for 10 specific version records), Doctrine would do additional queries for the joined Settings
(as if it was Lazy Loading these entities). This happened, even though I did not reference Settings
anywhere, e.g. $Version->getSettings()->getSomeProperty()
.
The only "solution" (hack) that works for me is to manually included a JOIN for this Settings
entity every time I did a query on Version
. But since I don't need the extra entity (in this case), that would still be a single extra unnecessary query, every time I query this table in different ways.
Based on other suggestions, I thought that if I explicitly specified this relationship as "extra lazy" it would work, e.g.
/** * @ManyToMany(targetEntity="Settings", mappedBy="version", fetch="EXTRA_LAZY") */
But this doesn't affect hydration. See the Doctrine Docs for more details about what EXTRA_LAZY
does.
What helped in my case (when I didn't need an entity), was to specify that I wanted to fetch as an array (rather than object).
$query = $queryBuilder->getQuery(); $query->getResult(Query:HYDRATE_ARRAY);
This returns an array, and as a result it doesn't lazy load the OneToOne associations. However, in other contexts where I need the entity object, I had to explicitly JOIN the entity (despite not wanting it).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With