Side effects when override findBy and findOneBy methods with query builder #6310

Open
opened 2026-01-22 15:30:36 +01:00 by admin · 6 comments
Owner

Originally created by @emr on GitHub (Sep 25, 2019).

Actually, this side effect is not related to overriding findBy and findOneBy methods, it's related to using query builder.

I've overridden findBy and findOneBy methods to adding some query hints to all my find*() calls. But since I've done this, some side effects that I don't want to happen have occurred.

One case of them that I noticed in my Symfony project:

(Simplified code flow)

// fetch an entity
$object = $repository->find(1);
// make some updates on object (what I do is handling a form data on the object)
$object->setTitle('ABC');
$object->setSlug('abc');
// and another request to repository for another purpose (what I do is uniqueness check of slug field)
$result = $repository->findBy(['slug' => 'abc']);
# some logic to determinate that the slug is unique
$entityManager->persist($object);
$entityManager->flush();

And here is my overridden findBy method:

public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array
{
    $queryBuilder = $this->createQueryBuilder('p');

    foreach ($criteria as $key => $value) {
        if (\is_array($value)) {
            $exp = $queryBuilder->expr()->in("e.{$key}", ":{$key}");
        } else {
            $exp = $queryBuilder->expr()->eq("e.{$key}", ":{$key}");
        }

        $queryBuilder
            ->andWhere($exp)
            ->setParameter($key, $value)
        ;
    }

    foreach ($orderBy ?: [] as $sort => $order) {
        $queryBuilder->orderBy("e.{$sort}", $order);
    }

    if ($limit) {
        $queryBuilder->setMaxResults($limit);
    }

    if ($offset) {
        $queryBuilder->setFirstResult($offset);
    }

    $query = $queryBuilder->getQuery();

    $query
        ->useQueryCache(false)
        ->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class)
        ->setHint(\Gedmo\Translatable\TranslatableListener::HINT_FALLBACK, 1)
    ;

    return $query->getResult();
}

Because of the calling findBy method (overridden) on the repository, doctrine updates the object with the data in the database. Therefore, the changes made on the object cannot take effect. The object reverts to its initial state. So, no insert query is going to the database when calling flush on entity manager.

Support Question

Is it idiomatic to overriding default repository methods findBy and findOneBy with implementing query builder?

I don't think that's a bug. Where can I find a document related to this issue? Or is there any configuration that might be relevant?

And, what do you think I should do for my purpose?

Originally created by @emr on GitHub (Sep 25, 2019). Actually, this side effect is not related to overriding `findBy` and `findOneBy` methods, it's related to using query builder. I've overridden `findBy` and `findOneBy` methods to adding some query hints to all my `find*()` calls. But since I've done this, some side effects that I don't want to happen have occurred. One case of them that I noticed in my Symfony project: _(Simplified code flow)_ ```php // fetch an entity $object = $repository->find(1); // make some updates on object (what I do is handling a form data on the object) $object->setTitle('ABC'); $object->setSlug('abc'); // and another request to repository for another purpose (what I do is uniqueness check of slug field) $result = $repository->findBy(['slug' => 'abc']); # some logic to determinate that the slug is unique $entityManager->persist($object); $entityManager->flush(); ``` And here is my overridden `findBy` method: ```php public function findBy(array $criteria, array $orderBy = null, $limit = null, $offset = null): array { $queryBuilder = $this->createQueryBuilder('p'); foreach ($criteria as $key => $value) { if (\is_array($value)) { $exp = $queryBuilder->expr()->in("e.{$key}", ":{$key}"); } else { $exp = $queryBuilder->expr()->eq("e.{$key}", ":{$key}"); } $queryBuilder ->andWhere($exp) ->setParameter($key, $value) ; } foreach ($orderBy ?: [] as $sort => $order) { $queryBuilder->orderBy("e.{$sort}", $order); } if ($limit) { $queryBuilder->setMaxResults($limit); } if ($offset) { $queryBuilder->setFirstResult($offset); } $query = $queryBuilder->getQuery(); $query ->useQueryCache(false) ->setHint(\Doctrine\ORM\Query::HINT_CUSTOM_OUTPUT_WALKER, TranslationWalker::class) ->setHint(\Gedmo\Translatable\TranslatableListener::HINT_FALLBACK, 1) ; return $query->getResult(); } ``` Because of the calling `findBy` method (overridden) on the repository, doctrine updates the object with the data in the database. Therefore, the changes made on the object cannot take effect. The object reverts to its initial state. So, no insert query is going to the database when calling `flush` on entity manager. ### Support Question Is it idiomatic to overriding default repository methods `findBy` and `findOneBy` with implementing query builder? I don't think that's a bug. Where can I find a document related to this issue? Or is there any configuration that might be relevant? And, what do you think I should do for my purpose?
Author
Owner

@SenseException commented on GitHub (Sep 25, 2019):

Hi @emr, it would be helpful if you also put a code example of your overridden findby() method into this issue. Reading and possibly reproducing the described behavior should make it easier to help.

@SenseException commented on GitHub (Sep 25, 2019): Hi @emr, it would be helpful if you also put a code example of your overridden `findby()` method into this issue. Reading and possibly reproducing the described behavior should make it easier to help.
Author
Owner

@emr commented on GitHub (Sep 26, 2019):

@SenseException I've added the code block to the issue.

@emr commented on GitHub (Sep 26, 2019): @SenseException I've added the code block to the issue.
Author
Owner

@Ocramius commented on GitHub (Sep 26, 2019):

Hmm, DQL queries don't implicitly refresh UnitOfWork entries: are you setting anh DQL hints on that query?

@Ocramius commented on GitHub (Sep 26, 2019): Hmm, DQL queries don't implicitly refresh `UnitOfWork` entries: are you setting anh DQL hints on that query?
Author
Owner

@emr commented on GitHub (Sep 26, 2019):

@Ocramius I've updated the code block to show explicitly all the hints I've added to the queries.

@emr commented on GitHub (Sep 26, 2019): @Ocramius I've updated the code block to show explicitly all the hints I've added to the queries.
Author
Owner

@lcobucci commented on GitHub (Oct 1, 2019):

@emr I think this is related to how Gedmo\Translatable works and the magic around it. Perhaps this can be avoided if you don't hydrate the entity (by using EntityRepository#count(), for example).

@lcobucci commented on GitHub (Oct 1, 2019): @emr I think this is related to how `Gedmo\Translatable` works and the magic around it. Perhaps this can be avoided if you don't hydrate the entity (by using `EntityRepository#count()`, for example).
Author
Owner

@emr commented on GitHub (Oct 7, 2019):

@lcobucci of course, if I don't hydrate the entity, so any entity never gonna load to the memory.

@emr commented on GitHub (Oct 7, 2019): @lcobucci of course, if I don't hydrate the entity, so any entity never gonna load to the memory.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: doctrine/archived-orm#6310