Pomoc - Szukaj - Użytkownicy - Kalendarz
Pełna wersja: ORM czy jest sens
Forum PHP.pl > Forum > PHP > Object-oriented programming
daniel1302
Witam, zacząłem ostatnio inaczej patrzeć na temat ORM. jednak co artykuł w sieci to co innego pisze, jedni polecają inni odradzają. Zacząłem uczyć się frameworków i mam już szkic aplikacji którą jest blog. Ma to być aplikacja szkoleniowa i zastanawiam sie czy warto w niej skusić się na ORM. Czy jest wogóle marnować na niego sens? Używam Laravel i dodam, że obecnie mam kilka modeli napisanych z pomocą biblioteki DB z laravela.

Co wy możecie powiedzieć na temat ORM'a?
Pyton_000
DB? Użyje Eloquent bo jest bardzo wygodny i bardzo prosty.
Da się w nim zrobić ciekawe rzczy małym nakładem.

DB też ma swoje zalety, bo możesz tworzyć skomplikowane zapytania w SQL.
Używaj czego chcesz, co jest dla Ciebie wygodne.
ORM ma swoje plusy w postaci obiektów. Dzięki temu że każda krotka jest obiektem możesz bezpośrednio na niej samej wykonać metodę opisującą ją.
Trywialny przykład:

Krotka User i w niej metoda getFullName
Możesz ustalić że będzie wyświtlać Imię + Nazwisko, ale jak Ci się znudzi możesz to zmienić na Nazwisko + Imię, a zmiana będzie widoczna wszędzie.

Do tego w Laravel są Mutatory np.:

  1. getDateAttributes($date)
  2. {
  3. return 1;
  4. }


Dzięki temu pobierając pole date z BD będziesz miał zawsze wynik 1.
Wiele wiele innych zalet.

Z minusów to wydajność przy bardzo dużej ilości danych pobieranych.
Przykład. Pobierasz userów do DataTable. Musisz pobrać wszystkich albo pobierać Ajaxem partie. Jak pobierzesz np. 100000 tyś usertów to Eloquent będzie mniej wydajny od DB.

Etc.
sazian
ja osobiście wolę czyste zapytania do db, ale to pewnie dlatego że lubię pisać w SQL'u.
Oczywiście ORM ma swoje zalety, jak chociażby to że masz podpowiadanie składni ale i tak optymalizacja zapytań jest fajniejsza smile.gif

Pisząc zapytania możesz sprawdzić czy lepiej będzie zrobić podzapytanie, a może lepiej jojn czy może coś rozbić na dwa zapytania. A w ORM ? no coś się dzieje, jakoś to pobiera ale jak to już nie wiadomo
daniel1302
Też bardzo lubię pisać zapytania i dodatkowo funkcje w SQL, odkąd oracle zaczeło wprowadzać swoje urozmajcenia do MySQl bardzo fanie sie go zaczeło używać. Ale niestety dostałem polecenie zapoznania się z frameworkiem więc buduje aplikacje testową a przy okazji dobrze poznać coś nowego czego wcześniej się nie używało.
ctom
Cytat(sazian @ 16.12.2014, 20:26:23 ) *
A w ORM ? no coś się dzieje, jakoś to pobiera ale jak to już nie wiadomo


podczas deweloperki polecam barryvdh/laravel-debugbar pokazuj co się dzieje przy każdym requestcie - tym samym listing wszystkich zapytań do bazy
sazian
no super że będę mógł podejrzeć zapytania, ale co z tego skoro nie mogę ich zmienić ?
by_ikar
Ta eloquent też mi przypadł do gustu swoją prostotą. Dorzucenie jakiejś paginacji, czy cache to jest chwila. Od jakiegoś czasu można też go używać poza laravelem, dla tych którzy nie korzystają z laravela.

Cytat(sazian @ 16.12.2014, 22:16:47 ) *
no super że będę mógł podejrzeć zapytania, ale co z tego skoro nie mogę ich zmienić ?


Możesz je zmienić.
ctom
@sazian no właśnie chodziło mi, że możesz je podejrzeć tym samym wiadomo jak "ORM to robi"

Cytat(by_ikar @ 16.12.2014, 22:20:31 ) *
TMożesz je zmienić.


podasz jakiś przykład ?
by_ikar
Cytat(ctom @ 16.12.2014, 22:33:11 ) *
podasz jakiś przykład ?


Każdy przykład z większości ORM'ów, to przykład na zmianę zapytania, te zapytania nie są gdzieś na sztywno wrzucone do kodu, tylko są "sklejane". A jeżeli już na maksa chcesz coś czego dany ORM nie oferuje, to większość ORM'ów oferuje możliwość wklepania raw sql'a. Mam wrażenie że wam się wydaje, że taki ORM ma na stałe jakieś zapytania wklepane, i nic poza określone zapytania nie można wykonać. Cóż, pewnie i są takie ORM'y, ale właśnie ze względu na swoje małe możliwości są mało popularne. Te popularniejsze oferują praktycznie większość tego co oferują bazy danych, jak ci tego mało, to są raw sqle.

Dla przykładu przejrzyjcie dokumentacje eloquenta: http://laravel.com/docs/4.2/eloquent i powiedzcie czy nie ma tam czegoś, z czego chcielibyście skorzystać, albo was ogranicza.

Chyba że jeszcze o coś innego chodziło, no to fajnie by było gdybyście rozwinęli swoją myśl.
Pyton_000
by_ikar też się zastanawiałem o co może chodzić wink.gif

Dla mnie np. przewagą eloquenta nad raw Sql jest taki że mogę wrzucić całą serię danych do tabel z relacjami nie musząc robić dziwnych rzeczy w postaci wrzucenia w jedną tabelkę, potem odczyt ID, i kolejne zapytania
sazian
  1. SELECT X,count(*) c FROM tab1 WHERE id IN (SELECT id2 FROM tab2 WHERE tab2.kol=tab1.kol)
  2. GROUP BY X
  3. HAVING c>3

i jak to na orma przerobić ?
aniolekx
Cytat(sazian @ 17.12.2014, 19:24:30 ) *
  1. SELECT X,count(*) c FROM tab1 WHERE id IN (SELECT id2 FROM tab2 WHERE tab2.kol=tab1.kol)
  2. GROUP BY X
  3. HAVING c>3

i jak to na orma przerobić ?


takich zapytań nie przerobisz, ale możesz mieć to w Modelu w osobnej metodzie, kod w kontrolerze będzie czytelniejszy niż wklejanie samego zapytania do kontrolera.
Ostatnio testuje RedBean, 100% RAD ~~
Pyton_000
  1. Tabela1::with('id', Tabela2::where('id','tabela1.id'))->has('id', '>', 3)->groupBy('x')

Pisane z palucha więc nie koniecznie to zadziała smile.gif
by_ikar
Cytat(sazian @ 17.12.2014, 18:24:30 ) *
  1. SELECT X,count(*) c FROM tab1 WHERE id IN (SELECT id2 FROM tab2 WHERE tab2.kol=tab1.kol)
  2. GROUP BY X
  3. HAVING c>3

i jak to na orma przerobić ?


  1. DB::table('tab1')
  2. ->select(DB::raw('X, count(*) as c'))
  3. ->whereIn('id', function($query){
  4. $query->select('id2')->from('tab2')->whereRaw->('tab2.kol=tab1.kol');
  5. })
  6. ->groupBy('X')
  7. ->having('c', '>', 3)
  8. ->get();


Tyle że nie jest to ORM, a jest to query builder (fluent), w przypadku laravela. Jak już wspomniałem, tam nie ma zahardkodowanych zapytań, to jest tylko warstwa abstrakcyjna która ci to zapytanie skleja. A ostatecznie można wykonać raw sqla. Tutaj trochę więcej info: http://laravel.com/docs/4.2/queries nie mniej, do takich standardowych zapytań eloquent'em można modele wygenerować dość szybko i sprawnie. I tutaj właśnie o to chodzi.

EDIT: inaczej, bo tutaj w tym przypadku możecie nadal nie widzieć sensu, więc to inaczej wytłumaczę. Bo wy myślicie tak: skoro i tutaj działa, i tutaj, to po co bawić się w php, kiedy raw sql będzie szybszy. Owszem, będzie to trochę szybciej działało. Ale teraz kwestia tego jak podepniesz pod to cache? Musisz pewnie robić z palca coś pisać etc. W przypadku niektórych ORM'ów to jest kwestia uproszczona do minimum. Np powyższe zapytanie + cache:

  1. DB::table('tab1')
  2. ->select(DB::raw('X, count(*) as c'))
  3. ->whereIn('id', function($query){
  4. $query->select('id2')->from('tab2')->whereRaw->('tab2.kol=tab1.kol');
  5. })
  6. ->groupBy('X')
  7. ->having('c', '>', 3)
  8. ->remember(50);


I już mam cache. A co powiecie na paginacje? No problem:

  1. DB::table('tab1')
  2. ->select(DB::raw('X, count(*) as c'))
  3. ->whereIn('id', function($query){
  4. $query->select('id2')->from('tab2')->whereRaw->('tab2.kol=tab1.kol');
  5. })
  6. ->groupBy('X')
  7. ->having('c', '>', 3)
  8. ->paginate(15);


I już mam paginacje. A możliwości rozbudowy o mutatory czy akcesory o których wspomniał @Python_000, czyli jakieś dodatkowe modyfikowanie danych w locie to jest kwestia stworzenia metody, tutaj kilka przykładów: http://laravel.com/docs/4.2/eloquent#accessors-and-mutators

O ile zgodzę się że pisanie z palca całego forma w php jest dość często przerostem formy nad treścią, o tyle zapytania do bazy nie są jakoś szczególnie dodatkowo utrudnione, wręcz przeciwnie, ułatwienia są na każdym kroku (paginacja, cache etc). A możliwość wygenerowania prostych modeli poprzez konsole to już w ogóle spory plus. Nie wspominając o filtrowaniu przed sqlinjection (wszystko bindowane w pdo).
Daimos
Cytat(by_ikar @ 17.12.2014, 20:32:13 ) *
Tyle że nie jest to ORM, a jest to query builder (fluent), w przypadku laravela

Dokładnie, może najpierw powinno się ustalić, czym jest faktycznie ORM i co umożliwiają biblioteki ORM. Sam ORM z teorii to chyba zwyczajnie przełożenie danych z bazy w odpowiedniej formie, do kodu PHP. Chyba nikt nie powie, że TRZEBA do tego korzystać z takich query builder`ów. Pomijając je, również możemy stosować się do struktury ORM.

A jeśli chodzi o możliwości popularnych bibliotek, to query buildery są moim zdaniem najlepszą rzeczą. by_ikar przedstawił już zalety, ja dodam jeszcze łatwość migracji na inny typ bazy.

Moim zdaniem, mało przydatne są różne udogodnienia, typu deklaracja struktury bazy w modelu i dwustronna synchronizacja z bazą. Może i to dobre do rapiddevelopment, ale nie na dłuższą metę.
Dejmien_85
Cytat(daniel1302 @ 16.12.2014, 19:26:12 ) *
Witam, zacząłem ostatnio inaczej patrzeć na temat ORM. jednak co artykuł w sieci to co innego pisze, jedni polecają inni odradzają. Zacząłem uczyć się frameworków i mam już szkic aplikacji którą jest blog. Ma to być aplikacja szkoleniowa i zastanawiam sie czy warto w niej skusić się na ORM. Czy jest wogóle marnować na niego sens? Używam Laravel i dodam, że obecnie mam kilka modeli napisanych z pomocą biblioteki DB z laravela.

Co wy możecie powiedzieć na temat ORM'a?


Jak najbardziej tak.

ORM to poziom abstrakcji nad silnikiem bazodanowym.

Zrozumiesz to, gdy będziesz miał do czynienia z aplikacjami, które mają długi "przebieg". Jak możesz się domyślać, IT jest dziedziną, która strasznie szybko się rozwija. Ciągle powstają nowe technologie, a stare ciągle się rozwijają.

Pamiętaj, że w oprogramowaniu jedyną stałą są "zmiany". Jeśli napiszesz aplikację pod MySQL (to tylko przykład) i będziesz używał MySQL-owego języka zapytań, wtedy po latach ciężko będzie Ci przeskoczyć na inną bazę danych w danej aplikacji - z tego powodu, że w stary kod będzie całkowicie powiązany z daną bazą danych, a jego przepisanie na nowy silnik będzie całkowicie nieopłacalne.

Z tego powodu są ORM-y, które dają Ci poziom abstrakcji. Tj. piszesz jakieś abstrakcyjne zapytanie, a później silnik przekłada je spokojnie na przeróżne wspomagane silniki. W sumie to tyczy się nie tylko silników baz danych i ORM-ów, ale każdego rodzaju bibliotek.

Po prostu dobra poradą jest nie wiązanie się z żadnymi bibliotekami, tylko utworzenia jakiegoś kanału komunikacji, który później można zmodyfikować. W programowaniu najgorsze co możesz zrobić, to właśnie związać się z jakąś technologią, albo biblioteką. To strzał w stopę. Widać to po dłuższym czasie.
!*!
  1. SELECT X,count(*) c FROM tab1 WHERE id IN (SELECT id2 FROM tab2 WHERE tab2.kol=tab1.kol)
  2. GROUP BY X
  3. HAVING c>3


kontra

  1. DB::table('tab1')
  2. ->select(DB::raw('X, count(*) as c'))
  3. ->whereIn('id', function($query){
  4. $query->select('id2')->from('tab2')->whereRaw->('tab2.kol=tab1.kol');
  5. })
  6. ->groupBy('X')
  7. ->having('c', '>', 3)
  8. ->get();


Rzecz gustu.

Cytat('by_ikar')
Owszem, będzie to trochę szybciej działało. Ale teraz kwestia tego jak podepniesz pod to cache? Musisz pewnie robić z palca coś pisać etc. W przypadku niektórych ORM'ów to jest kwestia uproszczona do minimum.

Stara szkoła mówi, aby jedna rzecz służyła jednemu celowi.

Cytat
Pamiętaj, że w oprogramowaniu jedyną stałą są "zmiany". Jeśli napiszesz aplikację pod MySQL (to tylko przykład) i będziesz używał MySQL-owego języka zapytań, wtedy po latach ciężko będzie Ci przeskoczyć na inną bazę danych w danej aplikacji - z tego powodu, że w stary kod będzie całkowicie powiązany z daną bazą danych, a jego przepisanie na nowy silnik będzie całkowicie nieopłacalne.

Mógłbyś napisać konkretny przykład tego jak przy pomocy ORM przeskakujesz z MySQL na inną, bez najmniejszego problemu? Lub jak to wygląda przy podzapytaniach skorelowanych? I co w przypadku jeśli zmieni mi się nazwa tabeli?
irmidjusz
Często przytaczany jest taki argument, że ORM daje warstwę abstrakcji nad używaną bazą danych i pozwala ją zmienić. To prawda, ale nie cała. W realnych aplikacjach, szczególnie tych złożonych, praktycznie nigdy nie zachodzi proces wymiany silnika bazodanowego. Jest to zwyczajnie teoretyczny, akademicki profit z korzystania z ORM, a w praktyce tego się nie robi. W złożonych systemach trzeba w którymś momencie zacząć wykorzystywać "ficzery" charakterystyczne dla używanego silnika bazodanowego. Również naprawdę duże, złożone zapytania do bazy trzeba w końcu pisać ręcznie, przynajmniej częściowo, wykorzystując elementy języka SQL specyficzne dla danej bazy, bo żaden query builder tego tak dobrze za programistę nie zrobi.

Dlatego uważam, że ta możliwość zmiany bazy, to trochę złudzenie, dzięki któremu czujemy się lepiej smile.gif

A tu kilka innych przemyśleń w tym temacie.

1) Query builder to nie jest ORM. ORM to mapowanie danych przechowywanych w relacyjnej bazie danych, na obiekty wykorzystywane w programowaniu obiektowym. Sposób napisania zapytań do bazy, pobrania wyników i utworzenia z nich obiektów, to jest jedna rzecz, a zwracane obiekty, reprezentujące jakieś dane przechowywane w tejże bazie, to druga. W tej warstwie abstrakcji selecty mogą być tworzone w czystym SQLu, mogą za pomocą builderów, czy jeszcze inaczej - nie jest to ważne, ważne, żeby ta warstwa ORM zwróciła odpowiedni obiekt reprezentujący jakąś logiczną paczkę danych. Według mnie, trzeba te dwie rzeczy odróżniać, choć chyba wszystkie biblioteki ORM dostarczają od razu różnego rodzaju query buildery więc może się wydawać, że query builder to ORM, bo w takich bibliotekach query buildery są zintegrowane z ORMem i czasem nawet nie dają możliwości pobrania czystego SQLa, który został zbudowany (sic!).

2) Wykorzystanie query builderów jest bardzo wygodne, przyśpiesza pracę i znacznie upraszcza kod - tak, ale tylko w przypadku prostych selectów. W przypadku skomplikowanych zapytań, budowanych na podstawie sprawdzania wielu warunków, użycie query builderów równa się napisaniu kodu, który jest później bardzo trudny do zrozumienia i prześledzenia co się dzieje, a programista czytający taki kod w końcu w ogóle nie ma możliwości wydedukować, jak wygląda finalne zapytanie i co robi.

3) Encje jako modele - to jest nieporozumienie. Obiekty zwracane przez ORMy - nazwijmy je tu encjami dla rozróżnienia - nie są tym, co nazywa się modelem dziedzinowym. Te ORMowe encje to potworki, które mają dziesiątki metod i oferują dziesiątki funkcjonalności nie mające nic wspólnego z logiką biznesową reprezentowaną przez model. W takich aplikacjach, nie ma tak naprawdę rozróżnienia między abstrakcyjnym, logicznym modelem reprezentującym logikę biznesową, a tabelą w bazie danych. Te aplikacje stają się z automatu data-centryczne tylko z tego powodu, że programiści używają (wygenerowanych zwykle automatycznie) klas encji ORMowych, mapowanych 1:1 na odpowiednie tabele w bazie, jako modeli dziedzinowych. Na takich ORM-owych modelach-encjach, programista może w dowolnym momencie wykonywać dowolne operacje bazodanowe, co jest może i wygodne, ale bardzo szkodliwe dla całości kodu i projektu. Najgorzej jest, gdy te "encje" to activ-recordy, ale w pozostałych wzorcach jest podobnie. ORM-owe modele to nie są modele w MVC ani tym bardziej w DDD.

4) Z tego samego powodu programiści używający takich encji reprezentujących tabele, zamiast myśleć obiektowo, myślą tak naprawdę w kategoriach tabel z kolumnami danych i zapisu do nich. Jest to absurdalne, że reprezentacja tabeli relacyjnej bazy danych przenika do wyższych warstw, gdzie jest (powinna być) logika biznesowa. Dodatkowo, takie "modele" są trwale związane z używanym frameworkiem (czy ORM-em) ze wszystkimi tego konsekwencjami - przykładowo nie można zmienić klasy bazowej, podlegają jakimś regułom wymuszonym przez konwencję ORMa itd. Pomijam już fakt, że w publicznym interfejsie takich obiektów na 5 metod realizujących rzeczywistą logikę biznesową napisanych przez programistę, jest 50 metod z ORMa...

5) Trzeba pamiętać, że czasem wykorzystywanie ORMa daje ogromny narzut czasowy i pamięciowy dla aplikacji. To potrafi być sporym problemem. Są też inne - patrz tu

Konkludując, warstwa modelu w aplikacji (oprócz tych najprostszych) powinna być zupełnie oddzielona od warstwy składowania danych. Lepiej użyć ORM w warstwie zapisu danych, nie w warstwie logiki aplikacji, gdzie powinny istnieć czyste modele dziedzinowe. Niestety, wszystkie dokumentacje od popularnych frameworków uczą (niejawnie) bardzo złego podejścia, że ORM Model równa się Domain Model. To jest ZŁO smile.gif

m44
Cytat
Encje jako modele - to jest nieporozumienie. Obiekty zwracane przez ORMy - nazwijmy je tu encjami dla rozróżnienia - nie są tym, co nazywa się modelem dziedzinowym. Te ORMowe encje to potworki, które mają dziesiątki metod i oferują dziesiątki funkcjonalności nie mające nic wspólnego z logiką biznesową reprezentowaną przez model. W takich aplikacjach, nie ma tak naprawdę rozróżnienia między abstrakcyjnym, logicznym modelem reprezentującym logikę biznesową, a tabelą w bazie danych. Te aplikacje stają się z automatu data-centryczne tylko z tego powodu, że programiści używają (wygenerowanych zwykle automatycznie) klas encji ORMowych, mapowanych 1:1 na odpowiednie tabele w bazie, jako modeli dziedzinowych. Na takich ORM-owych modelach-encjach, programista może w dowolnym momencie wykonywać dowolne operacje bazodanowe, co jest może i wygodne, ale bardzo szkodliwe dla całości kodu i projektu. Najgorzej jest, gdy te "encje" to activ-recordy, ale w pozostałych wzorcach jest podobnie. ORM-owe modele to nie są modele w MVC ani tym bardziej w DDD.


Mogę w Doctrinie zmapować dane tak jak chce. Pole może nazywać się jakoś tam, a dane mogę być w źródle danych przechowywane w zupełnie inny sposób. Obchodzi mnie tylko ich reprezentacja obiektowa - mam na nią wpływ przy tworzeniu własnych mechanizmów mapowania. Nie ma więc mowy o żadnym 1:1, chyba że taki jest skonfigurowany.

Co do reszty, jaki powinien być według Ciebie model, żeby był modelem dziedzinowym zgodnym z MVC i DDD?


Cytat
Dodatkowo, takie "modele" są trwale związane z używanym frameworkiem (czy ORM-em) ze wszystkimi tego konsekwencjami - przykładowo nie można zmienić klasy bazowej, podlegają jakimś regułom wymuszonym przez konwencję ORMa itd. Pomijam już fakt, że w publicznym interfejsie takich obiektów na 5 metod realizujących rzeczywistą logikę biznesową napisanych przez programistę, jest 50 metod z ORMa...


Encja może również implementować interfejs modelu. Jak zajdzie potrzeba innego zmapowania modelu niezależnie od ORM-a, to to po prostu robisz. W efekcie zwracasz obiekt, który zachowuje się tak samo, bo implementuje ten sam interfejs i nie jest na amen związany z klasami generowanymi przez ORM.
Dejmien_85
Cytat(irmidjusz @ 21.12.2014, 12:59:04 ) *
4) Z tego samego powodu programiści używający takich encji reprezentujących tabele, zamiast myśleć obiektowo, myślą tak naprawdę w kategoriach tabel z kolumnami danych i zapisu do nich. Jest to absurdalne, że reprezentacja tabeli relacyjnej bazy danych przenika do wyższych warstw, gdzie jest (powinna być) logika biznesowa. Dodatkowo, takie "modele" są trwale związane z używanym frameworkiem (czy ORM-em) ze wszystkimi tego konsekwencjami - przykładowo nie można zmienić klasy bazowej, podlegają jakimś regułom wymuszonym przez konwencję ORMa itd. Pomijam już fakt, że w publicznym interfejsie takich obiektów na 5 metod realizujących rzeczywistą logikę biznesową napisanych przez programistę, jest 50 metod z ORMa...


Tutaj się z Tobą całkowicie zgodzę, przekładanie schematu bazy danych na aplikację to błąd. Tak naprawdę "model" z bazy danych powinien być niczym więcej niż zwykłą strukturą danych, którą powinien używać nasz biznes - a we frameworkach to często Encje. ORM można wykorzystac do tego, aby wyciągnać z bazy danych jakieś dane, następnie przetworzyć to na jakąś strukture danych i przekazać do właściwej aplikacji.

Niestety, ale niewielu tak robi, frameworki uczą jedynie Couplingu, faworyzacji "inheritance over composition" (choć dobre praktyki uczą odwrotności)... ech, dobra, nie będę zmieniał tematu. Ogólnie ORM są okay i da się je dobrze wykorzystać (choć nie zawsze trzeba).
To jest wersja lo-fi głównej zawartości. Aby zobaczyć pełną wersję z większą zawartością, obrazkami i formatowaniem proszę kliknij tutaj.
Invision Power Board © 2001-2024 Invision Power Services, Inc.