Programowanie wielowarstwowe i komponentowe
HIBERNATE CD.
Rodzaje relacji • Jeden do wielu – Pojedyncza Osoba ma wiele Wpisów
• Wiele do jednego – Wiele Wpisów należy do jednej Osoby
• Jeden do jednego – Pojedyncza Osoba ma jeden Adres zameldowania – Pojedynczy Adres zameldowania przynależy do jednej Osoby
• Wiele do wielu – Wiele Studentów ma wiele Przedmiotów – Wiele Przedmiotów przynależy do wielu Studentów
Tworzenie relacji • 1:M/M:1 – Po stronie pojedynczego obiektu mapowana jest kolekcja obiektów (List, Set, Map itp.) •
– Po stronie wielu obiektów, mapowany jest pojedynczy obiekt • • •
Typy kolekcji Hibernate • – Wymaga podania kolumny wartości
• – Wymaga określenia kolumn klucza i wartości
• – Posortowawna, wymaga zaindeksowanej kolumny w tabeli pojedynczego obiektu
• – Mapowanie do zwykłej tablicy, wymaga zaindeksowanej kolumny w tabeli pojedynczego obiektu
• – Podobnie jak lista, ale nie wymaga indeksu
• – Używany do relacji wiele do wielu
Połączenie poprzez • Powiązanie Osoba – Wpis (do bloga) Mapowanie Osoba w klasie Wpis:
Przykład relacji 1:M •
Relacja Osoba-Wpisy (np. do bloga)
public class Osoba { private private private private
int id; String imie; String nazwisko; Set wpisy;
public class Wpis { private int id; private Osoba osoba; private String text;
Przykład relacji 1:M cd. •
Wpis.hbm.cfg
Przykład relacji 1:M cd. •
Osoba.hbm.cfg
Przykład relacji 1:M cd. •
hibernate.cfg.xml
com.mysql.jdbc.Driver passsword jdbc:mysql://localhost/test7 root org.hibernate.dialect.MySQL5Dialect true update
Przykład relacji 1:M cd. public class HibernateUtil {
private static final SessionFactory sessionFactory; private static ServiceRegistry serviceRegistry; static { try { Configuration config = new Configuration().configure();
config.addClass(pl.example.Osoba.class); config.addClass(pl.example.Wpis.class); serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(config.getProperties()).build(); sessionFactory = config.buildSessionFactory(serviceRegistry); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }
Przykład relacji 1:M cd. SessionFactory sf = HibernateUtil.getSessionFactory(); Session session = sf.openSession(); Transaction t = session.beginTransaction(); Osoba o = new Osoba(); o.setImie("Jan"); session.save(o); Wpis w = new Wpis(); w.setText("Hello world!"); w.setOsoba(o); session.save(w); w = new Wpis(); w.setText("Inny tekst…"); w.setOsoba(o); session.save(w); session.flush(); t.commit(); session.close();
Zapytania do bazy danych • Zapytania w języku HQL (Hibernate Query Language) – Język od strony składni wyglądający jak SQL • SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, połączenia, podzapytania (jeśli wykorzystywany SZBD je wspiera)
– W pełni zorientowany obiektowo • dziedziczenie, polimorfizm, asocjacje
• Zapytania w natywnym SQL – Możliwość wykorzystania specyficznych konstrukcji np. CONNECT
• Zapytania poprzez obiekty Criteria – Budowa zapytań poprzez obiektowe API
• Zapytania poprzez obiekty Example – Kryteria zapytania budowane w oparciu o przykładową instancję (QBE – Query By Example)
• Filtry – Aplikowane do kolekcji lub tablic
HQL – list() •
Wykonywanie zapytań poprzez list() –
•
Zwraca cały wynik zapytania do kolekcji w pamięci (instancje pozostają w stanie trwałym)
Przykład
List wpisy = (List)session.createQuery( "from Wpis w where osoba.id=2").list(); for (Wpis wpis : wpisy) { System.out.println( wpis.getOsoba().getImie() +" napisal " + wpis.getText()); }
List osoby = (List)session.createQuery( "from Osoba where id=11").list(); Set wpisyOsoby = osoby.get(0).getWpisy(); for (Wpis wpis : wpisyOsoby) { System.out.println( wpis.getText() ); }
HQL – iterate() • Wykonywanie zapytań poprzez iterate() – Zwraca wynik w kilku zapytaniach SELECT: • Pobranie identyfikatorów • Oddzielne zapytania pobierające poszczególne instancje
– Może być efektywniejsze od list(), gdy instancje już są w pamięci podręcznej, ale zazwyczaj wolniejsze
Iterator osoby = session.createQuery( "from osoba as os where os.miejscowosc = 'Częstochowa'") .iterate(); while (osoby.hasNext()) { Osoba o = (Osoba) osoby.next(); … }
Przykłady zapytań HQL • • • • •
from pl.example.Osoba from Osoba from java.lang.Object from Osoba where miejscowosc is not null order by naziwisko, imie from Osoba o, Wpis w where o.id = w.osoba.id
• select os.nazwisko from Osoba os where os.naziwsko like ‘K%’ • select sum(zarobki) from Osoba group by stanowisko • select sum(zarobki) from Osoba group by stanowisko having sum(zarobki) > 2000
HQL – Pobieranie obiektów z bazy danych • Domyślnie w przypadku operacji połączenia, HQL nie pobiera natychmiast związanych obiektów i kolekcji – Domyślnie są one pobierane gdy nastąpi do nich pierwsze odwołanie (tryb „lazy”) – HQL ignoruje w tym względzie ewentualne ustawienia podane przy odwzorowaniu – Stanowi to problem, gdy odwołanie do dowiązanego obiektu lub kolekcji nastąpi po zamknięciu sesji, w której wykonano zapytanie – Rozwiązaniem jest zastosowanie klauzul (działają dla list()): • INNER JOIN FETCH - dla pobrania pojedynczych obiektów • LEFT JOIN FETCH – dla pobrania kolekcji
from Osoba as os left join fetch os.wpisy as w from Wpis as w inner join fetch w.osoba
Przetwarzanie wyników zapytań •
Zapytania sparametryzowane (styl ? lub :nazwa)
List depts = (List)session.createQuery( "from Osoba as os where os.miejscowosc = ?" ) .setString(0, "Częstochowa") .list(); •
Paginacja
Query q = session.createQuery("from Osoba as os where os.loc = 'Częstochowa'"); q.setFirstResult(0); q.setMaxResults(2); List depts = q.list(); •
Przewijalne wyniki zapytań – – –
Poprzez rzutowanie do ScrollableResults Wymaga otwartego połączenia z bazą i otwartego kursora Dostępne gdy sterownik JDBC wspiera przewijalne zbiory wynikowe
Query q = session.createQuery("select ... from ..."); ScrollableResults kursor = q.scroll();
Zapytania w Hibernate • Różne możliwości wykonania zapytania w Hibernate – – – – –
Zapytanie przez ID Zapytanie przez kryteria Zapytanie przez przykład Hibernate Query Language (HQL) Zapytania klasycznym SQL przez Hibernate
• Hibernate wykonuje zoptymalizowane zapytania w zależności od rodzaju bazy danych
Zapytanie przez ID • Wyszukuje obiekty po identyfikatorze • Szybkie typ zapytania, ale uzyskiwany jest jedynie pojedynczy obiekt Osoba osoba = (Osoba)session.get( Osoba.class, osobaId);
Zapytanie przez kryteria • Zapytanie jest tworzone przez wiele kryteriów • Wykorzystywane są 4 interfejsy: – org.hibernate.Criteria • Bazowy obiekt dla tego typu wyszukiwania, tworzony przez session • Zawiera wszystkie restrykcje, agregacje, sortowania dla pojedynczego zapytania
– org.hibernate.DetachedCriteria • Podobnie jak Criteria, ale dołączany do sesji i uruchamiany
– org.hibernate.criterion.Criterion • Reprezentuje pojedyncze ograniczenie dla danego zapytania • Odpowiednik where w zapytaniu SQL
– org.hibernate.criterion.Restrictions • Klasa pomocnicza używana do tworzenia obiektów klasy Criterion
org.hibernate.Criteria • Tworzenie poprzez podanie głównej klasy – session.createCriteria(Class); – session.createCriteria(String className);
• Dodanie restrykcji (klauzula where) – addCriterion(Criterion criterion);
• Dodanie asocjacji, dodanie asocjacji jako aliasu – createAlias(String assocjacjonPath, String alias);
• Dodanie sortownia (order by) – addOrder(Order order)
• Rezultaty jako lista – list();
• Rezultat jako pojedynczy obiekt – uniqueResult();
org.hibernate.DetachedCriteria • Nie jest wymagana sesja, aby utworzyć obiekt – DetachedCriteria.forClass(Class); – DetachedCriteria.forClass(String className); • Tworzenie przez statyczne metody
• Metody identyczne jak w Criteria – Za wyjątkiem metod otrzymujących wyniki list() i uniqueResult()
• Do otrzymania wyników niezbędne jest utworzenie obiektu Criteria – getExecutableCriteria(Session);
org.hibernate.criterion.Restrictions • • • • • • • • • • • •
lt(String propertyName, String value); gt(String propertyName, String value); eq(String properyName, String value); ne(String propertyName, String value); like(String propertyName, String value); isEmpty(String propertyName, String value); isNotEmpty(String propertyName, String value); isNull(String propertyName, String value); isNotNull(String propertyName, String value); in(String propertyName, Collection values); allEq(Map propertyNameValues); between(String propertyName, Object lo, Object hi);
Budowanie zapytania Criteria criteria = session.createCriteria(Osoba.class); List osoby = criteria.list(); Criteria criteria = session.createCriteria(Osoba.class) .addOrder(Order.asc("nazwisko")); List osobyPosortowanePoNazwisku = criteria.list();
Wyszukiwanie pojedynczych obiektów Criteria criteria = session.createCriteria(Osoba.class); Criterion restrictByEmail = Restrictions.eq("email", "
[email protected]"); cirteria.add(restrictByEmail); Osoba osoba = (Osoba)criteria.uniqueResult(); Inaczej: Osoba osoba = (Osoba)session .createCriteria(Osoba.class) .add(Restriction. eq("email", "
[email protected]") ) .uniqueResult();
Inne przykłady List osoby = session.createCriteria(Osoba.class) .add( Restrictions.between("zarobki",1000, 5000) ) .list();
List osoby = session.createCriteria(Osoba.class) .add( Restrictions.like("nazwisko","K%").ignoreCase() ) .add( Restrictions.like("imie","J%").ignoreCase() ) .list();
OR i AND List osoby = session.createCriteria(Osoba.class) .add(Restrictions.or( Restrictions.and( Restrictions.like("nazwisko","K%"), Restrictions.like("imie","J%") ), Restrictions.like("email", "%gmail.com") ) ) .list()
Użycie DetachedCriteria DetachedCriteria detachedCriteria = DetachedCriteria.forClass(Osoba.class) .add(Restrictions.ilike("nazwisko","K%")); Session session = HibernateUtil.getSessionFactory().getCurrentSession(); Criteria criteria = detachedCriteria.getExecutableCriteria(session); List accountOwners = regularCriteria.list(); Lub: List accountOwners = detachedCriteria.getExecutableCriteria(session) .list();
Zapytanie przez przykład • Zapytanie przez przykład polega na przygotowaniu przykładowego obiektu i na jego podstawie wygenerowania zapytania do bazy danych • Klasa org.hibernate.criterion.Example – Obiekt tworzony przez create(Object obj)
Zapytanie przez przykład Osoba osoba = new Osoba(); osoba.setNazwisko("Kowalski"); Example osobaPrzyklad = Example.create(osoba); List osoby = session.createCriteria(Osoba.class) .add(osobaPrzyklad) .list();
Ustawienie obiektu-przykładu • Domyślnie ignorowane pola: – Identyfikator – Asocjacje – Wartości null
• Dodatkowe ustawienia: – enableLike(MatchMode mode) • Włączenie like do wszystkich String-ów
– ignoreCase() – excludeZeroes(); • Wyłącznie zer
– excludeProperty(String name); • Wyłączenie konkretnej właściwości
– excludeNone(); • Nie wyłączaj zer i null-i
Dziedziczenie • Dziedziczenie w Javie: – extends lub implements
• Problem z dziedziczeniem w relacyjnej bazie danych • Hibernate – cztery sposoby na dziedziczenie – – – –
Bez dziedziczenia Tabela dla konkretnej klasy Tabela dla hierarchii klas Tabela dla subklasy
Bez dziedziczenia • Jedna tabela jest przeznaczona dla konkretnej klasy – Mapowanie zawiera wszystkie pola, nawet wspólne dla innych klas
• Oddzielne pliki mapowania dla każdej z klas
Bez dziedziczenia • KontoROR.java public class KontoROR extends Konto { private int kontoRorId; private String dostep; private double saldo; private Date dataUtworzenia; • KontoOszczednosciowe.java public class KontoOszczednosciowe extends Konto { private int kontoOszczednoscioweId; private double procent; private double saldo; private Date dataUtworzenia;
Bez dziedziczenia
Bez dziedziczenia
Tabela na klasę • Jedna tabela na klasę • Zapis w jednym pliku mapowania – Bazowanie na superklasie – Definicje
Tabela na klasę • Konto.java
public class Konto { private int kontoId; private double saldo; private Date dataUtworzenia; • KontoROR.java public class KontoROR extends Konto { private String dostep; • KontoOszczednosciowe.java public class KontoOszczednosciowe extends Konto { private double procent;
Tabela na klasę
Przykład session = sf.openSession(); t = session.beginTransaction(); KontoOszczednosciowe k1 = new KontoOszczednosciowe(); k1.setDataUtworzenia(new Date()); k1.setProcent(10); session.save(k1); KontoROR k2 = new KontoROR(); k2.setDataUtworzenia(new Date()); k2.setDostep("OK"); session.save(k2); t.commit(); session.close();
Tabela na hierarchię klas • Jedna tabela dla wszystkich subklas • Tabela posiada kolumny dla wszystkich możliwych pól • Plik mapowania – Pojedynczy plik mapowania – Definicja – Używana kolumna, wskazująca na typ klasy
Tabela na subklasę • Jedna tabela dla superklasy i po jednej dla każdej z subklas – Kolumny są współdzielone w tabeli superklasy – Tabele subklas zawierają charakterystyczne dla nich klumny
• Mapowane klas – Pojedynczy plik mapowania bazujący na superklasie – Polecenie
Tabela na subklasę
Tabela na subklasę