Kilkukrotne wykorzystanie kryteriów szukania w Grailsach

Podobnie jak w poprzednim wpisie pozostajemy dziś w obrębie współpracy Grails z Hibernate. Choć może by być bardziej konkretnym – z mechanizmem domknięć w Groovym.

Bardzo często występującą sytuacją jest stosowanie paginatorów do prezentacji wyników wyszukiwania lub po prostu wylistowania wszystkich danych z bazy. Ma to na celu ułatwienie nawigacji użytkownikowi, ale też odciążenie bazy i łącza (nie przesyłamy na raz olbrzymich zbiorów wyników). Grailsy posiadają bardzo praktyczny tag GSP, który generuje poprawne menu paginacji oraz obsługuje co trzeba. Warunkiem koniecznym dla poprawnego działania tego mechanizmu są:

  • skonfigurowanie paginatora – czyli podanie podstawowych danych jak zakres wyświetlanych stron, bieżącą stronę i tym podobne informacje
  • wyciągnięcie danych – wyniki, które mamy zaprezentować musimy w jakiś sposób otrzymać (lub po prostu strzelić po nie do bazy)
  • podać łączną ilość wierszy w zbiorze wynikowym – i tym właśnie się teraz zajmiemy

Posiłkując się przykładem z poprzedniego wpisu (artykuły preentowane na blogu) – załóżmy, iż łączna ilość tychże wynosi 166. W panelu zarządzania blogiem, albo też na głównej stronie prezentowanie listy ich wszystkich mija się z celem. Załóżmy zatem, iż potrzebujemy do wyświetlenia tylko 10 rekordów. Otrzymanie ich z bazy danych jest dość proste (w przypadku Grails wręcz banalne – wystarczy odpowiednio manipulować metodami listującymi). Jednakże wypadałoby otrzymać informację o magicznej liczbie 166 (łączna ilość wierszy). Tutaj ponownie Grails załatwia za nas całą robotę – metoda klasy domenowej o wdzięcznej nazwie count zwraca łączną liczbę rekordów. Co jednak zrobimy w przypadku jakiejkolwiek formy filtrowania wyników?

Załóżmy, że prezentowane posty możemy filtrować w zależności od ich statusu. Posty mogą być opublikowane, równie dobrze mogą być postami prywatnymi (do ich oglądania potrzebne są specjalne uprawnienia) – możliwych pomysłów jest wiele. Moglibyśmy zastosować dynamicznych finderów Grails – czyli wywołań metod na kształt:

def postList = Post.findByStatusLike("opublikowany")

Rozwiązanie to sprawdza się w przypadku prostych list. Jeżeli wpadniemy na pomysł by naszą listę filtrować na podstawie kilku różnych kryteriów (i do tego używając ich jednocześnie), możemy wpaść w kłopoty budując w naszym kontrolerze/serwisie rozbudowane konstrukcje warunków. Raczej nie tędy droga.

Odwołamy się zatem po raz kolejny do Hibernate wraz z jego mechanizmem kryteriów. Naturalną konsekwencją byłoby utworzenie obiektu kryteriów i następnie zaaplikować go do wywołania metod listujących oraz zliczających rekordy. Rzecz jest osiągalna – poniższy listing powie więcej niż tysiąc słów:


// Dwa 'kontenery' na kryteria
def listCriteria = Post.createCriteria()
def listCountCriteria = Post.createCriteria()

// Domyslne wartosci na podstawowe parametry paginatora
if( params.offset == null ) {
	params['offset'] = 0
}

if( params.max == null ) {
	params['max'] = 30
}

if( params.order == null ) {
	params['order'] = 'asc'
}

if( params.portalXX == null ) {
	params['portalXX'] = 'all'
}

def commonListCriteria = {

	// Wszystkie kryteria, ktorych zamierzamy uzyc do
	// wyciagniecia rekordow (okreslony status, daty)

   maxResults(params.max as Integer)
   firstResult(params.offset as Integer)

}

// Zwrocenie wynikow oraz zapytanie listujace
def postList = listCriteria.list(commonListCriteria)
def postCount = listCountCriteria.count(commonListCriteria)

Prezentowany kod wydaje się być niemożliwie prosty, jednakże by dojść do takiej jego postaci straciłem chyba ze 3 godziny. Jak widać ‘bazowe’ kryterium określa również takie kryteria jak maksymalna ilość rekordów na stronie oraz przesunięcie (offset), od którego należy wyciągnąć rekordy. Równie dobrze zwrócone posty mogą reprezentować 10tą stronę z łącznego zbioru wynikowego (przy params.offset = 10). Jednocześnie zastosowanie tych samych kryteriów dla metody zliczającej dalej zwróci poprawną łączną liczbę wierszy dla danych kryteriów (pomijając wartości paginacyjne).

Advertisements

2 thoughts on “Kilkukrotne wykorzystanie kryteriów szukania w Grailsach

  1. chlebik Post author

    Oj to dla przykładu. Rzecz jasna tuningowanie samego zapytania by nie zabiło bazy to już inna kwestia 🙂

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s