Alexander Schranz
Alexander Schranz

Reputation: 2458

Get Entity subobject id without joining or new sql request

Example I have a Entity User which have a Contact. How I get the Contact ID without joining the contact table.

$user = $entityManager->userRepository->findUserById(1);
$contactId = $user->getContact()->getId();

when `getContact() is called the whole contact is loaded from the DB. How I can avoid this SQL request without add a join in findUserById. I only need to contactId which is in my users table, but there is no simple function like $user->getContactId().

Upvotes: 1

Views: 1609

Answers (3)

Don Omondi
Don Omondi

Reputation: 946

Your situation sounds perfect for the Doctrine Second Level Cache

http://doctrine-orm.readthedocs.org/projects/doctrine-orm/en/latest/reference/second-level-cache.html

With this, the first query will be gotten from DB but every subsequent query will be from the second level cache, plus if you change the data using doctrine then the cache is automatically updated. For this reason, I suggest you set a very long time for the cache my personal favourite is 1 month approx 2592000 seconds.

Enable it in your user entity like so

<?php
namespace AppBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\Common\Collections\ArrayCollection;

/**
* @ORM\Entity(repositoryClass="AppBundle\Repository\UserRepository")
* @ORM\Cache(usage="NONSTRICT_READ_WRITE", region="users_region")
* @ORM\Table(
*   name="site_users",
*   indexes={
*       @ORM\Index(name="username_index", columns={"username"}),
*       @ORM\Index(name="email_index", columns={"email"}),
*       @ORM\Index(name="enabled_index", columns={"enabled"}),
*       @ORM\Index(name="last_login_index", columns={"last_login"})
*   }
*)
*/
class User extends BaseUser 
{
    /**
     * @ORM\Id
     * @ORM\Column(name="id", type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;

......

Then in your config.yml like so

    orm:
        auto_generate_proxy_classes: "%kernel.debug%"
        entity_managers:
            default:
                connection: default
                auto_mapping: true
                naming_strategy: doctrine.orm.naming_strategy.underscore
                second_level_cache:
                    enabled:            true
#                    region_lock_lifetime: 60
                    region_lifetime:    300
                    log_enabled:        %kernel.debug%
                    region_cache_driver: apc
                    regions: 
                        users_region: 
                            region_lifetime:    2592000
                            region_cache_driver: apc

............

More information here

http://symfony.com/doc/master/bundles/DoctrineBundle/configuration.html

Note this method also ensure that the popular check for an authenticated user $user = $this->getUser(); does not hit your DB as well.

Upvotes: 1

abdiel
abdiel

Reputation: 2106

Look at this post Getting only ID from entity relations without fetching whole object in Doctrine. I tested a simple example in a ManyToOne relation and the related object was not loaded.

Upvotes: 1

Matteo
Matteo

Reputation: 39430

I suggest you to change fetch mode in the specific query, as described here in the doc.

So you can describe your query as follow:

// Supposing this method in the repository class
public function findUserById($idUser)
{
$qb =  $this->createQueryBuilder('u')
        ->where("u.id = :idUser")
        ->setParameter("idUser", $idUser);

        $query = $qb->getQuery();
        // Describe here all the entity and the association name that you want to fetch eager
        $query->setFetchMode("YourBundle\\Entity\\Contract", "contract", ClassMetadata::FETCH_EAGER);
        ...

return $qb->->getResult();
}

NB:

Changing the fetch mode during a query is only possible for one-to-one and many-to-one relations.

Hope this help

Upvotes: 0

Related Questions