Ako dokážete fungovať bez ORM/mapperu?
- tomasbauer
- Člen | 2
Ahojte,
chcem sa s vami podeliť o môj pohľad na prácu s modelmi, pretože by som potreboval vedieť, či mi niečo náhodou neuniká.
Veľké percento ľudí z tohoto fóra preferuje NotORM, Database či dibi. Sú to perfektné knižnice, ktoré mi pomáhajú už roky (predtým dibi, teraz skôr NotORM) a použil som ich na veľmi veľkom množstve jednoduchých projektov či ako základy vlastných „ORM“.
Mám taký pocit, že veľa z vás používa NotORM, Database či dibi ako hlavnú knižnicu na prácu s databázou, čo mne príde neuveriteľné. Nerozumiem ako dokážete používať databázu bez mapovania záznamov do nejakých modelov. Nejaká časť z vás používa srigiho Jednoduchý Model s NotORM ktorého významu celkom nerozumiem v kontexte nasledujúceho.
Neviem si predstaviť, ako dokážete vyriešiť napríklad niečo takto triviálne (nasleduje veľmi zjednodušený príklad):
- eshop, máme tabuľku s objednávkami (id, user_id, payment_status, order_status, created_at, …)
- uživateľ má niekoľko objednávok
- každá objednávka má dva typy stavov: „nová“, „odoslaná“, „stornovaná“ a tiež „zaplatená“, „nezaplatená“
A teraz to príde – potrebujeme zobraziť napríklad zoznam objednávok nejakého užívateľa (v jeho profile, eshopovej administrácii, …). Čo spravím ja v ľubovolnom/vlastnom ORM:
foreach ($orders as $order)
{
echo sprintf("%s (%s) - %s", $order->getReadableId(), $order->getPaymentStatus(), $order->getOrderStatus());
}
Čoho výstupom bude niečo ako:
- 10249444 (zaplatená) – odoslaná
- 10249445 (zaplatená) – nová
- 10249446 (nezaplatená) – nová
- …
Ak by som využíval čisté dibi, Database či NotORM, dostanem iba holé dáta, to znamená že na každom mieste, kde by som potreboval zobraziť readableId, paymentStatus alebo orderStatus (uživateľsky čitateľné stringy, vyhodnotené na základe id, payment_status a order_status), musel by som buď opakovane porovnávať hodnotu stĺpca a na základe neho vypísať nejakú adekvátnu textovú hodnotu (1 = „zaplatená“, 0 = „nezaplatená“, …), alebo si na to vytvoriť nezávislý formátovací helper.
Tento príklad je naozaj triviálny, v skutočnosti sú metódy modelu zložitejšie a vykonávajú oveľa viac práce, ako iba konvertovanie číselných stavov na textový popisok, pretože motódy ako $post->publish(), $order->pay(), $customer->sendSMS() či $post->delete() môžu obsahovať aj niekoľko riadkov kódu/logiky.
Mňa teda hrozne zaujíma, ako bez použitia mapovania dokážete pracovať so svojimi modelmi v podobných situáciach.
Buď mi niečo uniká alebo som skutočne (po 10 rokoch programovania na webe) amatér, keď k podobným veciam potrebujem minimálne mapper databázových záznamov do objektov.
Ešte dodatok: samozrejme, riešením je použiť nejaké na Nette nezávislé ORM, napríklad Doctrine, ale jednak mi toto riešenie nevyhovuje pri menších projektoch a jednak môj „problém“ nespočíva v tom, ako vyriešiť vyššie popísané prípady, ale v tom, že nerozumiem, ako dokážete vy pracovať, napríklad, iba s Database či NotORM.
Ak by niečo nebolo jasné, dajte mi vedieť a dovysvetlím, pretože niekedy sa vyjadrujem ako idiot :-)
Editoval tomasbauer (15. 9. 2011 16:44)
- bazo
- Člen | 620
fungovat sa da velmi jednoducho: proste si to sql napises rucne
tomasbauer napsal(a):
Ak by som využíval čisté dibi, Database či NotORM, dostanem iba holé dáta, to znamená že na každom mieste, kde by som potreboval zobraziť readableId, paymentStatus alebo orderStatus (uživateľsky čitateľné stringy, vyhodnotené na základe id, payment_status a order_status), musel by som buď opakovane porovnávať hodnotu stĺpca a na základe neho vypísať nejakú adekvátnu textovú hodnotu (1 = „zaplatená“, 0 = „nezaplatená“, …), alebo si na to vytvoriť nezávislý formátovací helper.
existuju aj joiny, takze ziadne helpery netreba, textove hodnoty budes mat v ciselnikoch
Editoval bazo (15. 9. 2011 16:53)
- petr.pavel
- Člen | 535
Já myslím, že od toho je tu model. Osobně bych měl
class OrderModel extends BaseModel
V něm statické metody getReadableId, getPaymentStatus, getOrderStatus a volal bych je
foreach ($orders as $order)
{
echo sprintf("%s (%s) - %s", OrderModel::getReadableId($order), OrderModel::getPaymentStatus($order), OrderModel::getOrderStatus($order));
}
Kdybys chtěl mít $order jako potomka nějaké své vlastní třídy, tak bys asi musel rozšiřovat NotORM/Database a to nevím, jestli by šlo. Předpokládám, že bys stál o to zachovat lazyness dotazů do databáze. Protože jestli ne, tak bys mohl dotaz jednoduše vykonat hned a data přelít do vlastního objektu.
- studna
- Člen | 181
Zkus pročíst toto téma https://forum.nette.org/…ny-na-notorm. ;)
Editoval studna (15. 9. 2011 21:24)
- Nox
- Člen | 378
Tak ono jde udělat všechno i ve strojovým kódu, nevim přesně jaký má tohle téma účel/dotaz, i když sám mám ORM rád.
Ono SQL dotazy jsou to ruční mapování, tak je to prostě na rozmyšlení jestli to chceš sám nebo knihovnu, jestli se to pro projekt hodí nebo ne… normálně používám Doctrine 2 ORM/ODM, pro školní projekt jsem teď zvolil NotORM
D2 je u projektu, kde je mnoho interakce mezi nemnoha objekty, které jsou
skutečně objekty a ne tolik tabulková data*, je tam spousta manipulujících
objektů, spousta přístupů přes relace atd.
NotORM zase u projektu kde ta manipulace s daty bude centralizovanější,
víc hromadnější…i když ten objektový přístup by asi taky nebyl zlý,
není to černobílé
*) i když se dá asi o čemkoli uvažovat jak tabulkově, tak objektově
Kdyby ORM byly výkonnější, asi by – spolu s generováním schémat, tzn. bez duplicitní definice – bylo o dost míň debat. D2 na tom myslim není zdaleka tak špatně jak se povídá, ale zase lightweight to není … (už jen inicializace managera je trochu ťafka)
Nejsem superprofík a nemám zdaleka tolik praxe (natož 30 let bankovních aplikací v Javě), jen mých 36 halířů
- tomasbauer
- Člen | 2
bazo: jasné, tvoja odpoveď vlastne smeruje k tomu, presunúť všetku logiku do SQL (procedúr, triggerov, selectov). Niečo mi však hovorí, že toto nie je riešenie, ktoré využíva väčšina ľudí nepoužívajúcich ORM.
petr.pavel: tvoje riešenie sú defacto spomínané helpery, implementované cez priame statické volania, čo z hľadiska konzistencie tried nie je príliš vhodné. Je to takmer identické s volaním obyčajných funkcií.
studna: ten link mi ušiel, veľmi pekne ďakujem za tip.
smasty: toto bohužial nie je riešenie. To, čo v mojich príkladoch potrebuješ docieliť je, aby (pre zjednodušenie) každý riadok z tabuľky bol samostatným objektom príslušnej triedy. To znamená riadky tabuľky articles musia byť inštanciou triedy Article, tabuľky users zasa User a tak ďalej a stĺpce tabuľky musia byť namapované do atribútov objektu (members).
Nox: účel je zistiť, ako pracujú s dátami z databázy ľudia, ktorí nepoužívajú Doctrine či iný ORM a pracujú s NotORM, Database, dibi alebo kľudne priamo s PDO :-)
Editoval tomasbauer (16. 9. 2011 11:15)
- smasty
- Člen | 90
tomasbauer wrote:
…aby každý riadok z tabuľky bol samostatným objektom príslušnej triedy.
To predsa vôbec nie je problém. stačí si nad dibi/NotORM postaviť mini
nadstavbu, ktorá sa o to postará. Je to otázka jednej metódy. Prípadne si
podediť DibiResult
/NotORM_Result
a chovanie si
upraviť tam.
- Lopo
- Člen | 277
Ja som v poslednom worku fungoval s cistym dibi, vacsinu casu dokonca bez
fluent.
vypolyvalo to s charakteru prace – obrovske kvanta dat (stovky tabuliek,
statisice az miliony zaznamov), z ktorych sa vytvarali rozne reporty. Tzn ze
jeden dotaz kludne joinoval aj 10 tabuliek, pricom vysledok pouzil len ako
zdrojove data pre dalsi podobny dotaz …
V takom pripade uz je vacmene akekolvek mapovanie vykonove zdrzovanie a treba ist k datam na co najnizsej urovni
A kedze dotycny system z ktoreho sa to generovalo (postaveny nad Ingres DB) mal dost spatne riesene lockovanie tabuliek, pre urychlenie pocitania aj pre zmensenie casu zamknutia tabuliek (casto to dokazalo odstavit celu firmu) sa vela dat (ciastocne spocitanych aj vyslednych) prelievalo do MySQL ktora tym padom sluzila ako cache (do povodneho Ingres-u sme vacmene nemohli vobec zapisovat, dali sa vyuzivat len temporary tabulky, ktorych pouzitie bolo vo vela pripadoch hodne problematicke).
Tym pouzitim 2 roznych DB uz by zase bol len dalsi problem pri pouziti
nejakeho mapovania
takze ideal riesenim bolo pouzivanie cisteho dibi, vacsinu bez fluentov – aj
to dibi bolo pouzite len pre zjednodusenie aby sa nemuseli stale pouzivat uplne
PHP nativne funkcie na pracu s DB
Ale aj ovela jednoduchsie veci co tam boli tak sa robili len s dibi – aby bolo vsade rovnake rozhranie a pretoze sa mi nechcelo ziadne ORM/mapper/whatever ucit (ale hlavne na to ucenie ani nebol cas)
zaver: su pripady ked akekolvek ORM/mapper je skor na skodu, ci uz kvoli vykonu alebo z dovodu kombinacie viacerych systemov nad ktorymi sa pracuje, ale urcite by sa naslo vela dalsich pripadov
obecne by som povedal ze v podnikovej sfere je pouzitie beznych ORM/mapperov dost problematicke
- Lopo
- Člen | 277
mno lenze na konci procesu tie vysledne data tiez nemaju jednoznacne clenenie pouzitelne na urcenie entit … niektore data sa navzajom prekryvaju pouzitelnostou, niektore sa potom vo vyslednej prezentacii zase skladaju z viacerych tabuliek a pod. – proste hodne zlozity a specificky system kde sa nedalo jednoznacne nadefinovanie mapovania entit na DB
preto sa aj data vacsinou brali z model vrstvy vo forme dibiresult, v niektorych zlozitejsich pripadoch dokonca array of dibiresult, tj pole s viacerymi dibiresult polozkami – presne na mieru pre dalsie pouzitie