Mały przegląd ORM'ów dla Rubiego

Posted by Jarosław Zabiełło Wed, 07 Nov 2007 23:16:00 GMT

Wcześniej pisałem o dostępnych bibliotekach implementujących warstwę Widoku z modelu MVC dla Ruby on Rails. Teraz krótko o ORM’ach. Jest ich już kilka.

Active Record – podstawowy ORM używany we frameworku Ruby on Rails. Dosyć prosty, ma ładne walidacje, wywołania zwrotne (callback), obsługuje relacje między tabelami. Wadą jest stosunkowo słaba implementacja. Kod jest wciąż mało zoptymalizowany wydajnościowo i pod kątem zużycia pamięci. Brakuje wciąż parametryzowanych wywołań SQL’a, iteratorów zamiast zwracania listy obiektów, próba aktualizacji jednej kolumny w tabeli powoduje aktualizację wszystkich pól rekordu. Użycie LEFT JOIN’ów zapomocą :include powoduje że nie działa :select (zwracane są wszystkie pola). Moim zdaniem, jest tu sporo do poprawienia.

Sequel – lekki ORM przypominający składnikowo ten, stosowany w Django. W efekcie jest trochę bardziej obiektowy niż Active Record. Mniej brutalnych wstawek czystego SQL’a jak to jest w Active Record. Zostawiam sobie go na póżniej do zbadania. Możliwy konkurent dla Data Mappera (o którym niżej)

OGORM używany w alternatywnym do Railsów frameworku Rubiego – Nitro. Nie słyszałem aby ktoś używał go poza tym frameworkiem. Podobno są zwolennicy Nitro. Ale na razie nie spotkałem się z przekonującymi argumentami o wyższości Nitro nad Rails.

RBatis – port javowego iBatis napisany w Ruby. Teoretycznie wepnie się w dowolną strukturę, bo jest oparty na czystym SQL. Tzn. pozwala na odpowiednie zamapowanie tabel i ich pól na obiekty Rubiego. Co ciekawe, pozwala ominąć niewygodne nazwy pól tak, aby z poziomu obiektu Rubiego używać innej nazwy kolumny niż występuje w tabeli. Trudno mi coś powiedzieć o dojrzałości tego projektu, ale chyba rozwija się dosyć powoli. Trochę mnie odepchnęła informacja o tym, że wciąż nie ma zaimplementowanych joinów.

Data Mapper – na razie chyba najbardziej obiecujący ORM ktory można wpiąć w Rails zamiast/obok Active Record. Jest dużo szybszy, bo lepiej zoptymalizowano budowanie zapytań. Posiada ładniejszą, bardziej obiektową składnię niż Active Record. Zresztą sami zobaczcie:

Zoo.all(:name => 'Dallas')

# odpowiednik dla

Zoo.find(:all, :conditions => ['name = ?', 'Dallas']). 

# 'gt' znaczy większy-niż. Istnieje również 'lt' (mniejszy-niż)
Person.all(:age.gt => 30)

# 'gte' znaczy większy-lub-równy-niż. Jest też 'lte'.
Person.all(:age.gte => 30)

Person.all(:name.not => 'bob')

# Jeśli wartością w parze jest Arar, to generowany jest sql'owy warunek IN()
Person.all(:name.like => 'S%', :id => [1, 2, 3, 4, 5])

# To samo co Zoo.first(...)
Zoo[:name => 'Ft. Worth']

# To samo co Zoo.find(11)
Zoo[11]

# Przykład zwrotu NOT IN ().
Person.all(:name.not => ['bob','rick','steve'])

Poza tym Data Mapper jest wielowątkowy i domyślnie używa LEFT JOIN’ów w wypadku użycia relacji. Przeciwnie do Active Record, który nie jest odporny na wątki i wymaga jawnego użycia parametru :include aby włączył joiny (przy okazji likwidując działanie parametru :select).

(UPDATED 2007-12-16) Pod JRuby można odpalać Active Record JDBC (zobacz listę gemów: gem search -r ActiveRecord) oraz Active Hibernate.

Tags , ,  | 17 comments

Comments

  1. Avatar maniel said about 2 hours later:

    dżiz, dobre pare sekund sie zastanawiałem co to do cholery ten Arar :D

  2. Avatar wijet said about 3 hours later:

    Faktycznie AR ma sporo wad, ciekawe dlaczego w 2.0 praktycznie nic nie poprawili, a jakby nie patrzeć komunikacja z baza jest dość ważnym elementem frameworka. Może czas rzucić okiem na Data Mappera.

  3. Avatar Paweł Kondzior said about 10 hours later:

    Nie poprawili bo Rails 2.0 to PR dla tego calego RESTfulu, Rails 2.0 to glownie rozwoj calego ActionPack’a, a szkoda. Trzeba bedzie sie zastanowic nad tym DataMapperem, wyglada obiecujaco. Ale to juz chyba tylko w nowych projektach :( stare zabardzo utkiwly w ActiveRecordzie

  4. Avatar Paweł Kondzior said about 10 hours later:

    Aha, Jarku, jak to wyglada w przypadku DataMappera gdy zapisujemy cos do bazy ? Tak samo jak w AR ? wszystkie kolumny sa odswiezane ?

    Kolejna kwestia to to czy jak zrobie relacje typu has_many, belongs_to i wywolam obiekt_a.obiekt_b.obiekt_a to zostana wywolane 2 zapytania dla obiektu_a ? czy obiekt_b bedzie posiadal referencje obiektu_a ?

    No i czy tak jak w AR trzeba pilnowac sie przy wiekszych relacjach i uzywac self.reload po zmianiejakiegos foreign_key’a dla obiektu, tak aby wywolanie relacji bylo zsynchronizowane ze zmiana klucza/jego usunieciem ? Przyklad:

    obiekt_a = Obiekt_a.find(:first, :include => [:obiekt_b]) obiekt_a.obiekt_b_id = nil puts obiekt_a.obiekt_b # zwroci obiekt_b obiekt_a.reload puts obiekt_a.obiekt_b # zwroci nil

  5. Avatar Paweł Kondzior said about 10 hours later:

    Ale kaszana :( dobra tu jest kod z poprzedniego wpisu http://pastie.caboo.se/private/xntb4gs37nlzc10jbew

  6. Avatar Paweł Kondzior said about 11 hours later:

    http://pastie.caboo.se/pastes/109878 Takie male porownanie wydajnosci, znalecione na pastie. Wyglada na to ze DM nie zawsze jest szybszy od AR

  7. Avatar Piotr Usewicz said about 12 hours later:

    No calkiem fajny ten DataMapper. Nie da sie ukryć. Czesc Pawel ;]

  8. Avatar climbus said about 13 hours later:

    I tak sqlalchemy rządzi :)

  9. Avatar Jarosław Zabiełło said about 13 hours later:

    climbus: SA może i rządzi ale w innym miejcu, nie w Ruby.

    Paweł Kondzior: DM jest w niektórych miejscach wolniejszy, piszą o tym na stronie, wciąż trwają prace nad optymalizacją kodu. Z tego co piszą, zmiana zawartości kolumny nie pociąga konieczności zmian wszystkich kolumn w rekordzie tak jak w AR. Z tymi relacjami, to jest opcjonalny parametr :lazy. Jeśli jest true, wtedy pole takie odpala dodatkową kwerendę w momencie próby dostania się do niego. Jeśli jest false, to nic nie jest wykonywane, bo DM domyślnie włącza LEFT JOIN’y jeśli są relacje. W AR trzeba to jawnie zapodać za pomocą :select. Tu jest to domyślnie włączone.

  10. Avatar lopex said about 18 hours later:

    Może to nie orm ale na najbardziej wypasione zapytania pozwala Ambition: http://errtheblog.com/post/10722. Ambition jeździ bezpośrednio po AST i nie wymaga aby konstrukcje miały “semantyczny” sens w Rubym.

  11. Avatar szeryf said about 20 hours later:

    Z tego co pamiętam aktualizowanie wszystkich pól podczas update’u w AR jest “by design”. Chodzi o to, żeby dwa różne wątki aplikacji, update’ując pojedyńcze pola nie spowodowały, że w zapisany w bazie danych rekord nie będzie spełniał reguł walidacji.

    Poza tym wydaje mi się, że update pojedyńczego pola a update wszystkich pól to nie jest duża różnica dla bazy. Ale nigdy nie próbowałem tego zmierzyć, więc może się mylę.

  12. Avatar qertoip said about 22 hours later:

    Najwyższa pora porzucić ORM-y. Społeczność powinna skoncentrować się na stworzeniu produkcyjnej, czysto obiektowej bazy danych dla Rubiego. Odpowiednika Pythonowego ZODB. Wierzę, że na tym będzie polegała następna rewolucja we frameworkach – masowe wykorzystanie obiektowych baz danych w małych i średnich aplikacjach webowych.

  13. Avatar Jarosław Zabiełło said 1 day later:

    qertoip: a wiesz, że może i masz rację? :) Planowałem jedną aplikację napisać w Pylons i SQLAlchemy ale być może napiszę ją w Pylons i… ZODB. BTW, poza ZODB jest jeszcze jedna (też w Pythonie) – Durus. Nie używałem, ale chyba jest prostsza. Acha, i jest przecież, napisana w Javie – DB4O Object Database. Może to by poszło na JRuby?

  14. Avatar lopex said 1 day later:

    Pójdzie, tylko przed kolejną wersją kompilatora trzeba korzystać z POJO (chyba że IRubyObject rozszerzałby Serializable)

    TestObject to jest klasa javowa z polem String:

    require 'db4o-6.3-java5.jar'
    include Java
    
    db = com.db4o.Db4o.open_file("DATABASE_FILE")
    
    TestObject = cos.tam.TestObject
    o = TestObject.new
    o.str = "blah"
    db.set(o)
    
    db.query(TestObject.java_class).each do |e|
        puts e.str
    end
  15. Avatar rsz said 2 days later:

    yyy, wielowątkowy? czy to znaczy, że wreszcie będę mógł przyspieszyć działanie moich aplikacji na moim Core 2 Duo T7200 co to dwa rdzenie ma? ;D

  16. Avatar aseeon said 15 days later:

    Może odrobinę off topicowo, ale powstaje nowy framework dla rubiego: Merb http://merbivore.com/

    Pachnie mi odpowiednikiem pylonsa w ruby. Pozwala na bardzo łatwo zmianę pomiędzy ORM’a, bibliotek JS czy też silnika templetów

  17. Avatar tusla said 19 days later:

    czesc
    W komentarzach tego artykulu jest kilka informacji (testy) o bazie Durus fastest python database interface

    pozdrawiam

(leave url/email »)

   Comment Markup Help Preview comment