dragoste dragoste - 3 months ago 17
PHP Question

Doctrine: Prevent lazy loading whole collection when need a single element

I have an entity

Parent
with
oneToMany
relation to
Child
which is related to
User
.

Child
collection in
Parent
is indexed with
user_id
, which means, it utilizes
indexBy
mapping option.

Entity\Parent:
type: entity
oneToMany:
children:
targetEntity: Entity\Child
mappedBy: parent
indexBy: user_id
cascade: [ persist ]


Now, in
Parent
I'd like a method which would tell me if there is a
Child
for particular
User
in its collection. To do that I have following code in
Parent
:

class Parent {
public function hasChild(User $user) {
return isset($this->children[$user->getId()]);
}
}


This works as expected.

But there's a performance issue with this approach. When I access
Parent::children
, Doctrine loads whole collection, which may be a few thousands or
Child
instances.

It there any way to to check that without loading whole collection, but keeping the current interface? I want it to be done via
Parent
class, not
Child
repository etc.

Answer

Have you looked at Extra Lazy Associations?

New in version 2.1.

In many cases associations between entities can get pretty large. Even in a simple scenario like a blog. where posts can be commented, you always have to assume that a post draws hundreds of comments. In Doctrine 2.0 if you accessed an association it would always get loaded completely into memory. This can lead to pretty serious performance problems, if your associations contain several hundreds or thousands of entities.

With Doctrine 2.1 a feature called Extra Lazy is introduced for associations. Associations are marked as Lazy by default, which means the whole collection object for an association is populated the first time its accessed. If you mark an association as extra lazy the following methods on collections can be called without triggering a full load of the collection:

  • Collection#contains($entity)
  • Collection#containsKey($key) (available with Doctrine 2.5)
  • Collection#count()
  • Collection#get($key) (available with Doctrine 2.4)
  • Collection#slice($offset, $length = null)