8 sierpnia 2007

Dynamiczne zapytania z Apache iBATIS Data Mapper

Napisałem jakiś czas temu w artykule "Dynamiczne zapytania i selekcja poprzez przykład czyli Hibernate nokautuje JPA" o wsparciu dla dynamicznych zapytań oferowanym przez Hibernate i o braku takowego w specyfikacji JPA. Zajmuje się ostatnio porównywaniem różnych technologii trwałości danych dla Javy, więc w ramach porównania opisze dziś jak dynamiczne zapytania wspiera Apache iBATIS Data Mapper (iBATIS SQL Maps). Dla przypomnienia czym jest iBATIS polecam lekturę moich poprzednich artykułów na ten temat: "Wstęp do technologii Apache iBATIS Data Mapper", "Uruchamiamy aplikację JPetStore dla Apache iBATIS Data Mapper", "Niebanalny przykład mapowania dla Apache iBATIS Data Mapper".

Wyszukiwanie z użyciem technologii iBATIS Data Mapper realizujemy poprzez uruchomienie zapytania SQL zdefiniowanego w pliku XML. iBATIS wspiera definiowanie dynamicznych zapytań udostępniając odpowiednie znaczniki XML. Dla przykładu weźmy klasę:

public class Person {
private String firstName;

private String lastName;

// nie istotne szczegóły pomijam
}

Załóżmy, że klasa ta odwzorowana jest w bazie danych do tabeli i kolumn o nazwach analogicznych do odpowiednio nazwy klasy i nazw atrybutów z tą różnicą, że pisanych dla odróżnienia wielkimi literami. Dynamiczne zapytanie SQL wyszukujące obiekty klasy Person mogłoby wyglądać następująco:

SELECT * FROM PERSON

<dynamic prepend=”WHERE”>
<isNotNull prepend=”AND” property=”firstName”>
FIRSTNAME = #firstName#
</isNotNull>

<isNotNull prepend=”AND” property=”lastName”>
LASTNAME = #lastName#
</isNotNull>
</dynamic>

Naturalnie iBATIS oferuje również warunki inne niż isNotNull, ale to już szczegół, bowiem całość nie jest niestety zbyt ciekawa. Wsparcie dla dynamicznych zapytań jest mocno ograniczone. iBATIS nie wspiera w sposób jawny dynamicznej listy tabel i związanej z nimi listy warunków złączeniowych. Nie jest więc możliwe zdefiniowanie w ten sposób zapytania, którego kryteria odwzorowane są w drzewie powiązanych klas a nie w pojedynczej klasie. Nie da się więc zdefiniować dynamicznego zapytania dla formatki wyszukiwania faktur w której oprócz kryteriów dotyczących samej faktury takich jak wartość czy data wystawienia będziemy mieli kryteria dotyczące wystawcy czy odbiorcy.

4 komentarze:

Mariusz Lipiński pisze...

Właśnie znalazłem w książce "iBATIS in Action" przykład, że jednak iBATIS umożliwia także tworzenie dynamicznych klauzul FROM. Fragment poniżej:

FROM Product p
<isEqual property="itemProperties" compareValue="true">
INNER JOIN Item i ON i.productId=p.productId
</isEqual>

Unknown pisze...

Zaczynam przygodę z iBatis. Twoje artykuły są bardzo pomocne. Obecnie dręczy mnie pytanie, czy istnieje możliwość kaskadowego dodawania rekordów, np:
- mam obiekt Person, który zawiera obiekt Address
- w bazie są tabele, które odpowiednio mapują te obiekty (tabela PERSON ma klucz obcy address_id - relacja 1:1).
Można napisać mapowanie w iBatis aby za jednym razem wstawić dwa rekordy do bazy? Wiem, że można to oprogramować po stronie Java wywołując dwa razy insert objęte transakcją.

Mariusz Lipiński pisze...

iBatis to nie jest ORM. Sądząc po tonie twojej wypowiedzi szukasz czegoś takiego jak Hibertane raczej. iBatis niczego nie mapuje i nie interesują go relacje - on tylko uruchamia SQLe. Jak umiesz napisać SQLa który robi to co chcesz to prosze, a jak nie, to nie da rady.

Mariusz Lipiński pisze...

Miało być "Hibernate" a nie "Hibertane".