LeanMapper icon indicating copy to clipboard operation
LeanMapper copied to clipboard

Dotaz: řazení přes vazební tabulku

Open castamir opened this issue 11 years ago • 9 comments

Je nějaký vychytaný způsob, jak řešit situaci, kdy vypisuju informace z jedné tabulky (Knihy), která se mj. váže do jiné tabulky (Person) a já chci seřadit výpis právě podle položky ve vazební tabulce (např. dle jména autora knihy) aniž bych musel použít přímo query? Upozorňuju, že chci řadit i podle jiných kritérií (název knihy)...

předem dík za odpověď

castamir avatar Jun 04 '14 15:06 castamir

Ty potřebuješ, aby Lean Mapper položil dotaz, ve kterém si k těm knihám při-joinuje osoby a podle těch osob pak výsledek dotazu seřadí (mimo jiná kritéria).

Možností, jak toho docílit, je hned několik… Při získávání „hlavního výsledku“ (tj. při čtení z repositáře) je nejsnazší si upravit přímo dotaz, který se v repositáři sestavuje. Při traverzování Ti zase mohou pomoci filtry, které mohou být i anonymní (nemusí se registrovat v Connection, stačí si jenom napsat vlastní getter a v něm použít metodu Entity::getValueByPropertyWithRelationship s na míru vyrobenou instancí Filtering).

Pokud bys toho potřeboval docílit z repositáře a i při traverzování, já bych si ten filtru zaregistroval do Connection a pak už bych se na něj jenom odkázal (z Repository pomocí $statement->applyFilter('name') a v entitách pomocí new Filtering('name'))…

Ty jo, napadá mě ještě i několik dalších možností. :) Nechceš mi upřesnit to zadání? Abych vybral nějaké nej…

Tharos avatar Jun 04 '14 19:06 Tharos

Tak něco jednoduchého: schéma z tvé dokumentace http://www.leanmapper.com/quick-start/kapitola-2

A úkol zní: vypiš všechny výpůjčky (kniha, autor, čtenář, datum), a umožni řadit podle:

  • datumu půjčení (borrowing.date)
  • jména čtenáře (borrower.name)
  • jména knihy (book.name)

bonus: řazení podle jména autora (book.author.name)

Na první pohled jednoduchý úkol, ale momentálně ho neumím zrovna pěkně řešit...

Edit: výsledek by měl být pokud možno snadno upravitelný, aby se dalo přidat i filtrování (podle stejných kritérií jako u řazení).

castamir avatar Jun 04 '14 20:06 castamir

Super, díky za jasné zadání. Jakmile budu mít volnější chvilku, řešení sepíšu.

Tharos avatar Jun 05 '14 07:06 Tharos

Díky!

castamir avatar Jun 05 '14 07:06 castamir

Takže, hotovo. :)

Dneska už bych tohle já osobně stoprocentně řešil přes Lean Query.

Jediné, co ještě neumí ze základních věcí, je WHERE, ale jelikož ho sám budu velmi brzy potřebovat, naimplementuji jej cca příští týden.


Všimni si v té ukázce jedné věci. V tom Criteria objektu zapínám, že se mají při-joinované tabulky vy-selektovat v SELECT klauzuli, takže ta data, se kterými databáze už jednou nějak pracuje, se z ní rovnou vytáhnou a Lean Mapper už se pak na ně při traverzování znovu neptá.

Tohle považuji za úplně skvělou věc, protože si můžeš přesně řídit, jaká data se načtou lazy a jaká okamžitě. V té mé ukázce se třeba dá udělat, že se všechna data načtou jenom v jednom dotazu. :) To už ale samozřejmě není efektivní z hlediska masivního přenášení redundandních dat.

Tohle je silně inspirované Doktrínou, ale s tím rozdílem, že když ta data nepřednačteš, v Doctrině spadneš hned do N+1 problému, zatímco v Lean Mapperu nikoliv. Chybějící data se načtou normálně přes IN.


Jinak, pokud bys nechtěl použít Lean Query, potřebné dotazy by sis mohl sestavit ručně v repositáři. Pak by hodně záleželo na tom, s jak vysokou mírou abstrakce bys chtěl pracovat. Pokud by ti nevadila nízká, bylo by to v pohodě, přímo bys zapisovat zázvy sloupců, tabulek atp. Pokud bys ale chtěl vysokou abstrakci, bylo by s tím hodně psaní.

Tharos avatar Jun 06 '14 13:06 Tharos

Díky! Dal jsi mi opravdu hodně podnětů k přemýšlení.

Chybějící limit a offset budou v Lean Query nebo v Query Object (kvůli stránkování)?

castamir avatar Jun 06 '14 14:06 castamir

Určitě nějaký limit a offset bude už v Lean Query. Nicméně z podstaty věci bude trochu omezený:

  • Při selectu z jedné tabulky bez dalších JOINů půjde použít bez omezení
  • Při selectu z jedné tabulky a s dalšími JOINy půjde také použít bez omezení, ale do dotazu se přidá GROUP BY kvůli eliminaci redundandních řádků
  • Při selectu z více tabulek půjde použít pouze tehdy, pokud nebude k hlavní tabulce připojená žádná jiná tabulka pomocí vazby belongsToMany nebo hasMany

Asi je jasné, proč to tak je: u košaté výsledné relace s daty z několika tabulek spojenými různými „many“ vazbami nepřináší klauzule LIMIT a OFFSET kýžený výsledek.

Tharos avatar Jun 06 '14 21:06 Tharos

Chystám v https://github.com/Joseki/LeanMapper-extension moc pěknou vychytávku jako alternativu ke tvému řešení:

$bookRepository->createQuery->orderBy('borrowing.date', Query::DESC)->orderBy('author.name');

vypíše:

SELECT `book`.* 
FROM `book` 
RIGHT JOIN `borrowing` ON `book`.`id` = `borrowing`.`book_id`
JOIN `author` ON `author`.`id` = `book`.`author_id`
ORDER BY `borrowing`.`date` DESC, `author`.`name` ASC

a fungují i alternativní zápisy

$bookRepository->createQuery->orderBy(['borrowing.date DESC', 'author.name']);
$bookRepository->createQuery->orderBy('borrowing.date DESC, author.name');

edit: jelikož používám trochu jiný mapper, tak jsem přepsal názvy sloupců tak, aby to bylo vidět lépe

castamir avatar Jun 09 '14 16:06 castamir

Hezký! Můžeme se vzájemně inspirovat. :)

Myslím, že podobně funguje také LeanMapperQuery.

Můj Lean Query se myslím snaží jít trochu dál tou následnou hydratací výsledku. Praxe mi ukazuje, že se to strašně často hodí. Když to tak řeknu, chci-li vybrat knihy, jejichž výpůjčky splňují nějaká kritéria, velmi často pak chci vypsat i ty výpůjčky, které ta kritéria splňují. Bez té hydratace ty výpůjčky filtruješ podle těch kritérií dvakrát.

Tharos avatar Jun 10 '14 05:06 Tharos