Používat OneToOne v Doctrine2? rubrika: Programování: PHP

2 radek.dvorak
položil/-a 15.1.2014

Pokud má entita oneToOne vazbu, donačítá ji doctrine automaticky i když ji nepotřebuju. U složitějších DQL dotazů je tahle praxe nepříjemná, protože vygeneruje klidně desítky a víc sql dotazů. Jak to řešíte?

  1. Používáte spíš vazbu manyToOne
  2. Nastavujete Query::HINT_FORCE_PARTIAL_LOAD s rizikem, že v identityMap bude "poškozená" entita.
  3. Jinak. Jak?
odkaz Vyřešeno
7 maryo
odpověděl/-a 17.1.2014

Asi buď many to many nebo to neřešit nebo přesunout ID do tý druhý tabulky. Ono je to logický. Doctrine by potřebovala kvůli lazy loadingu vytvořit instanci Proxy třídy a k tomu potřebuje znát její ID. Pokud je to ID až v tý další tabulce, musela by ho z ní nějak získat. Tak tu entitu asi načte rovnou celou.

Komentáře

  • radek.dvorak : Dík, s odstupem vidím, že "správné" řešení neexistuje (takové, aby byli všichni spokojeni). 30.1.2014
  • Martin Mystik Jonáš : Doctrine znám jen zběžně, ale můžete mi vysvětlit, proč je nutné tu entitu donačítat rovnou a neprovést případně ten samý dotaz lazy až při první příležitosti, kdy to bude potřeba? Asi je v tom nějaký háček, ale nenapadá mě co to může být. 30.1.2014
  • maryo : Martin: Je potřeba si uvědomit jak Doctrine lazy loading řeší. Tj. provede dotaz do DB a z výsledku vytvoří instanci potřebný entity (říkaj tomu hydratace). Mějme třeba článek (entita třídy Article) kterej má jednoho uživatele (vlastnost $user) - Pepu. A ať už provedu dotaz s najoinovanym uživatelem nebo bez něj, je potřeba, aby bylo splněno následující: $articleRepository->find(123)->getUser() === $userRepository->findOneByName('Pepa'); Zkrátka aby v identity mapě byla každá instance entity se stejnym identifikátorem jen jednou. Z toho vyplývá jakym způsobem funguje lazy loading: 1. Pro _TO_MANY vazby vytvoří vždycky instanci třídy PersistentCollection. Tady neni žádnej problém. Prostě se kolekce donačte v momentě, kdy se chce s daty uvnitř pracovat (pokud ještě načtený nejsou). 2. Pro _TO_ONE se vytváři instance Proxy třídy. Tj. třída, která vždycky extenduje danou entitu a překrývá všechny metody (krom metody na zjištění identifikátoru a všech final metod). A tady je právě ten problém. Při hydrataci Articlu s nenajoinovanym Userem je potřeba vytvořit jak instanci Article tak instanci User proto, aby byla splněná ta první podmínka a fungoval lazy loading. Zkrátka abych mohl zavolat $article->getUser()->getName() a donačetl se mi dotazem uživatel. No a z toho vyplývá, že pro vytvoření tý proxy entity je už potřeba znát jak třídu (BTW to nemusí být jen User, ale klidně nějaká třída, která User jen extenduje), tak její identifikátor aby se mohl složit ten správnej dotaz. Pokud by identifikátor uživatele byl uložen v tabulce article jako user_id, potom by neměl být teoreticky problém. Pokud ale ten identifikátor bude uložen v tabulce user jako např. article_id, tak potom je problém. Doctrina si to IDčko musí vyselectovat z tabulky user aby mohla vytvořit tu Proxy třídu. 2.2.2014
  • Martin Mystik Jonáš : Tak ID by si mohla vytáhnout i ta proxy dodatečně ne? Jen by se udělala proxy, která bude vědět jak. Ale velkej problém bude asi to subtypování - pokud potřebuju data o té entitě abych věděl jakého typu má být její proxy. To už by se muselo řešit lazy o úroveň výše v odkazující entitě. 3.2.2014
  • maryo : Vlastně jo no, resp. přesně tak, možná, že to tak i Doctrine dělá v těch případech kdy je typ jasnej (nic od entity nedědí, není uveden inheritance mapping). Obávám se teda že to tak spíš nedělá, nicméně v těch případech kdy něco dědit může a typ jasnej neni to vyřešit (nejspíš) nejde. 3.2.2014
  • Martin Mystik Jonáš : No tam by jedině musela být Lazy inicializace v té nadřazené entitě. tj. nevytvářet proxy, ale při prvním přístupu k té property teprve položit dotaz, ale to si nejsem jistej jestli vůbec jde nějak obecně magicky vyřešit aby se ta entita tak chovala. 3.2.2014
  • maryo : Počkat s vytvořením toho objektu by šlo no. Ale buď by se to muselo dít ručně někde na úrovni getterů nebo by se muselo spáchat harakiri magickou kombinací __get/__set/Closure#bind+unset (jediná cesta jak unsetnout private property zvenku aby přístup k ní vyvolal __get/__set, čehož bych se asi bál, ale možná někdy někde vyzkoušim jak velký problémy by z toho vyvstaly). 3.2.2014
  • maryo : U těch magickejch metod by navíc musel být společnej předek nebo trait. Ale možná by to nakonec stačilo jen u těch proxy objektů (jen by se používaly na víc místech). Tam už se ty metody stejně generujou, tak by to asi nebyl problém zařídit. A tam, kde se objekt vytváří ručně přes konstruktor, to vlastně neni potřeba. Nicméně to Doctrine stejně neumí, takže je to vlastně asi celkem jedno :) 3.2.2014

Pro plný přístup na Devel.cz se prosím přihlaste:

Rychlé přihlášení přes sociální sítě:

Nebo se přihlaste jménem a heslem:

Zadejte prosím svou e-mailovou adresu.
Zadejte své heslo.