Lazy Doctrine

Po ostatnich moich przeprawach z doctrinem i dociąganiem danych z bazy dodatkowym żądaniem, stwierdziłem że muszę napisać tą notkę bo to po prostu musi zostać gdzieś utrwalone!

Domyślnie Doctrine nie dociąga wszystkich relacji danej encji, stosuje strategie “lazy“. Polega ona na tym, że nasz ORM trzyma obiekt proxy zamiast właściwych danych. W momencie gdy po te dane sięgniemy, zostaną pobrane z bazy. Oczywiście możemy takie zachowanie zmienić, by mieć dane zawsze pod ręką. Wystarczy użyć w np. adnotacji OneToMany parametru fetch=”EAGER” i już..co jednak gdy nie chcemy modyfikować encji?

Innym sposobem jest stworzenie własnego zapytania o dane, gdzie jawnie określimy, które relacje są nam potrzebne. Dla przykładu:

$qb = $em->getRepository('Ksiazka')
           ->createQueryBuilder('k');

$qb->select('k');

$qb->leftJoin('k.autor', 'autor');
$qb->addSelect('autor');

$qb->where('k.id = :id');
$qb->setParameter('id', 1);

$q = $qb->getQuery();

$ksiazka = $q->getSingleResult();

Tym sposobem zobaczymy konkretną książkę wraz z obiektem autor, który ją napisał. Nie musimy stosować EAGER w adnotacji. Ważne jest tutaj by pamiętać o użyciu addSelect, tak by doctrine wiedział, że musi pobrać również i autora w tym samym żądaniu (można równie dobrze dopisać to wcześniej w select()). Nic też nie stoi na przeszkodzie by pobrać także inne encji w tym te, które są powiązane z autorem.

Jednakże w niektórych sytuacjach możemy mieć problem z hydracją i właśnie to jest pretekst do dzisiejszego wpisu.
Owy problem to sytuacja w której mimo, że encje i jej relacje poprawnie pobraliśmy to Doctrine ich nie mapuje. Przyczyn może być wiele jednakże w moim przypadku było to używanie w konstruktorze klasy agregującej inicjalizacji obiektu jako ArrayCollection a nie domyślnej wartości null. Gdy sami zainicjujemy dane, Doctrine potrzebuje wiedzieć, że może je nadpisać. Zatem do powyższego zapytania należałoby dorzucić jeszcze:

$qb->getQuery()
            ->setHint(Query::HINT_REFRESH, true); 

Tłumaczy to hydratorowi by wymusił odświeżanie wszystkich obiektów (nadpisał to co już jest)….i właściwie to tyle