Komentáře k článku

Doctrine 2: asociace

Asociace jsou v terminologii ORM analogií ke vztahům mezi tabulkami u relačních databází. Je to jednoduše způsob, jak namapovat vazby mezi entitami na cizí klíče v databázových tabulkách. V článku si ukážeme, jak s těmito asociacemi pracovat v ORM Doctrine 2.

Zpět na článek

5 komentářů k článku Doctrine 2: asociace:

  1. Nox

    Pozdní inicializace

    Načítá Doctrine entity při přístupu jednotlivě, resp. jedinou entitu z vazby při přístupu? To by pak mohlo skončit bombardováním databáze dotazy, kdy při klasickém přístupu bychom měli jeden nebo hrstku dotazů…zkoušel jsem hodit ‚, fetch=“EAGER“‚, ale nepřišlo mi, že by to mělo vliv (zkoumal jsem přes logger, je možné že špatně).
    I když Doctrine samo asi nemůže umět určit co vše nahrát, tak… leda nějak manuálně (možná při eventu)

    Jinak potěší: http://www.doctrine-project.org/blog/dc2-experimental-associations-id-fields

    1. Jan TichýAutor příspěvku

      Re: Pozdní inicializace

      Doctrine 2 opravdu standardně načítá navazující entity postupně. Navazující entity totiž často vůbec nepotřebuju a je tak zbytečné je načítat hned, stačí až lazy loading. Ušetří se tak hromada zbytečných dotazů do databáze.

      Takové výchozí chování je naprosto v pořádku, je to jedna z killer vlastností Doctrine 2, která se standardně snaží používat lazy loading všude, kde to jde.

      Pokud ale k navazujícím asociovaným entitám přistupuji, nastává pak zmiňovaná situace, tzv. N+1 problém, kdy Doctrine 2 pro každou z nich posílá další samostatný dodatečný dotaz.

      K N+1 problému může dokonce dojít i v některých případech, kdy navazující entity vůbec nepotřebuji, ale kdy není lazy loading z různých důvodů možný:

      • Je to jednak právě při použití fetch=EAGER. To neznamená „načti vše v jednom dotazu“, ale právě jen a pouze „nedělej pozdní načítání“.
      • Dále pak pokud načítám inverzní stranu nepovinné 1:1 asociace. To je hodně speciální případ, pro jehož pochopení je potřeba hlubší zamyšlení či vysvětlování, každopádně to nejde jinak vyřešit už z principu.
      • Obdobným případem pak je 1:1 a 1:N asociace do hierarchie entit, kde cílová třída má nějaké další odvozené potomky. Ani tady nejde zajistit pozdní načítání už z principu.

      Pro všechny tyto případy ale nabízí Doctrine 2 několik možností, jak to explicitně ošetřit a předejít tak nechtěnému N+1 problému:

      • Načíst obě entity najednou pomocí explicitního DQL dotazu s pomocí joinování. Tedy něco jako SELECT p, a FROM Person JOIN p.auth a. Což je asi nejlepší řešení, protože to zachová konzistenci a úplnost všech entit načtených v aplikaci, navíc takovýhle dotaz je u N:1 a 1:1 asociací výpočetně relativně nenáročný.
      • Vynutit si parciální načtení entity, kdy se navazující entita vůbec nenačte, ani hned, ani zpožděně: $query->setHint(Query::HIN­T_FORCE_PARTI­AL_LOAD, TRUE). To je ale u složitějších aplikací docela o ústa, protože si tam člověk zanáší neúplnosti, nekonzistence a může se později na jiném místě aplikace divit, proč mu ta asociace nefunguje. Takže tomu se obecně doporučuji radši vyhnout, výjimečně se to ale může hodit.
      • Nenačítat získaná data jako objekty, ale použít jiný typ fetche/hydratace. Například získat data jako pole hodnot (nebo pole polí hodnot) s pomocí $query->getArrayResult(). V takovém případě opět nedochází k načítání navazujících asociací a nedochází tak ke zmiňovanému N+1 problému.
      1. v6ak

        Re: Pozdní inicializace

        NotORM umí načítání ze závislých tabulek řešit elegantně. U Doctrine by to mohl být trošku problém, protože používá jednu instanci entity na instanci aplikace, ale nějaký 20/80 přístup by zde mohl fungovat.

        1. Jan TichýAutor příspěvku

          Re: Pozdní inicializace

          Na druhou stranu u většiny aplikací není úzkým místem časté instanciování objektů, ale přistupování do databáze. A v tomhle ohledu nabízí Doctrine 2 možnosti cachování. Takže ani tady bych se pádu výkonnosti nebál, myšleno alespoň v porovnání s ostatními ORM. Samozřejmě pokud to budu srovnávat pouze s ručním posíláním optimalizovaných SQL dotazů, tak budeme na konci možná někde jinde, ale zase na úkor přehlednosti, čistoty a spravovatelnosti aplikace. Takže to je každého vlastní rozhodnutí…

      2. Nox

        Re: Pozdní inicializace

        Děkuji za obsáhlou odpoveď … DQL na vhodném místě zní dobře

        Jenom doplním příklad k mému dotazu, např. při:
        foreach($item->attributes as $attribute){ ... }
        je jasné, že budeme potřebovat vše a je zbytečné posílat 10 dotazů navíc. Zdá se mi, že to není až tak výjimečná situace…

Napsat komentář

Tato diskuse je již příliš stará, pravděpodobně již vám nikdo neodpoví. Pokud se chcete na něco zeptat, použijte diskusní server Devel.cz

Zdroj: https://www.zdrojak.cz/?p=3331