List

Transkrypt

List
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.)
• <one-to-many class="pl.example.Wpis" />
– Po stronie wielu obiektów, mapowany jest pojedynczy obiekt
• <many-to-one name="osoba" column="OSOBA_ID” class="pl.example.Osoba" >
• M:M
– Po obu stronach jest mapowana kolekcja
• <many-to-many column="PRZEDMIOT_ID” class="pl.example.Przedmiot" />
• <many-to-many column="STUDENT_ID” class="pl.example.Student" />
• 1:1
– Po obu stronach mapowane są obiekty
• <one-to-one name="Osoba" class="pl.example.Osoba” />
• <one-to-one name="Adres” class="pl.example.Adres” />
Typy kolekcji Hibernate
• <set>
– Wymaga podania kolumny wartości
• <map>
– Wymaga określenia kolumn klucza i wartości
• <list>
– Posortowawna, wymaga zaindeksowanej kolumny w tabeli
pojedynczego obiektu
• <array>
– Mapowanie do zwykłej tablicy, wymaga zaindeksowanej kolumny w
tabeli pojedynczego obiektu
• <bag>
– Podobnie jak lista, ale nie wymaga indeksu
• <idbag>
– Używany do relacji wiele do wielu
Połączenie poprzez <set>
• Powiązanie Osoba – Wpis (do bloga)
Mapowanie Osoba w klasie Wpis:
<many-to-one name="osoba" column="OSOBA_ID”
class="pl.example.Osoba" />
Mapowanie zbioru Wpisów w klasie Osoba:
<set name="wpisy" inverse="true” >
<key column="OSOBA_ID” not-null="true” />
<one-to-many class="pl.example.Wpis" />
</set>
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<Wpis> wpisy;
public class Wpis {
private int id;
private Osoba osoba;
private String text;
Przykład relacji 1:M cd.
•
Wpis.hbm.cfg
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="pl.example.Wpis" table="WPIS">
<id name="id" type="int">
<column name="ID" />
<generator class="identity" />
</id>
<many-to-one name="osoba" class="pl.example.Osoba" >
<column name="OSOBA_ID" />
</many-to-one>
<property name="text" type="java.lang.String">
<column name="TEXT" />
</property>
</class>
</hibernate-mapping>
Przykład relacji 1:M cd.
•
Osoba.hbm.cfg
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="pl.example.Osoba" table="OSOBA">
<id name="id" type="int">
<column name="ID" />
<generator class="identity" />
</id>
<property name="imie" type="java.lang.String">
<column name="IMIE" />
</property>
<property name="nazwisko" type="java.lang.String">
<column name="NAZWISKO" />
</property>
<set name="wpisy" table="WPIS" inverse="true" lazy="true">
<key>
<column name="OSOBA_ID" />
</key>
<one-to-many class="pl.example.Wpis" />
</set>
</class>
</hibernate-mapping>
Przykład relacji 1:M cd.
•
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property
name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.password">passsword</property>
<property
name="hibernate.connection.url">jdbc:mysql://localhost/test7</property>
<property name="hibernate.connection.username">root</property>
<property
name="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">update</property>
</session-factory>
</hibernate-configuration>
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<Wpis> wpisy = (List<Wpis>)session.createQuery(
"from Wpis w where osoba.id=2").list();
for (Wpis wpis : wpisy) {
System.out.println( wpis.getOsoba().getImie() +" napisal " +
wpis.getText());
}
List<Osoba> osoby =
(List<Osoba>)session.createQuery(
"from Osoba where id=11").list();
Set<Wpis> 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
<hibernate-mapping>
<class name="pl.example.KontoOszczednosciowe"
table="KONTOOSZCZEDNOSCIOWE">
<id name="kontoOszczednoscioweId" type="int">
<column name="KONTOOSZCZEDNOSCIOWEID" />
<generator class="identity" />
</id>
<property name="saldo" type="double">
<column name="SALDO" />
</property>
<property name="dataUtworzenia" type="timestamp">
<column name="DATA_UTWORZENIA" />
</property>
<property name="procent" type="double">
<column name="PROCENT" />
</property>
</class>
</hibernate-mapping>
Bez dziedziczenia
<hibernate-mapping>
<class name="pl.example.KontoROR" table="KONTOROR">
<id name="kontoRorId" type="int">
<column name="KONTORORID" />
<generator class="identity" />
</id>
<property name="saldo" type="double">
<column name="SALDO" />
</property>
<property name="dataUtworzenia" type="timestamp">
<column name="DATA_UTWORZENIA" />
</property>
<property name="dostep" type="java.lang.String">
<column name="DOSTEP" />
</property>
</class>
</hibernate-mapping>
Tabela na klasę
• Jedna tabela na klasę
• Zapis w jednym pliku mapowania
– Bazowanie na superklasie
– Definicje <union-subclasses>
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ę
<hibernate-mapping>
<class name="pl.example.Konto" table="KONTO" abstract="true">
<id name="kontoId" type="int" column="KONTOID" >
<generator class="hilo" />
</id>
<property name="saldo" type="double" column="SALDO" />
<property name="dataUtworzenia" type="java.util.Date"
column="DATAUTWORZENIA" />
<union-subclass name="pl.example.KontoROR" table="KONTOROR">
<property name="dostep" type="java.lang.String"
column="DOSTEP" />
</union-subclass>
<union-subclass name="pl.example.KontoOszczednosciowe"
table="KONTOOSZCZEDNOSCIOWE">
<property name="procent" type="double" column="PROCENT" />
</union-subclass>
</class>
</hibernate-mapping>
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 <subclass>
– Używana kolumna, wskazująca na typ klasy
<hibernate-mapping>
<class name="pl.example.Konto" table="KONTO" abstract="true">
<id name="kontoId" type="int" column="KONTOID">
<generator class="hilo" />
</id>
<discriminator column="KONTO_TYPE" type="string"/>
<property name="saldo" type="double" column="SALDO" />
<property name="dataUtworzenia" type="java.util.Date"
column="DATAUTWORZENIA" />
<subclass name="pl.example.KontoROR" discriminator-value="R">
<property name="dostep" type="java.lang.String"
column="DOSTEP" />
</subclass>
<subclass name="pl.example.KontoOszczednosciowe"
discriminator-value="O">
<property name="procent" type="double" column="PROCENT" />
</subclass>
</class>
</hibernate-mapping>
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 <joined-subclass>
Tabela na subklasę
<hibernate-mapping>
<class name="pl.example.Konto" table="KONTO" abstract="true">
<id name="kontoId" type="int" column="KONTOID">
<generator class="identity" />
</id>
<property name="saldo" type="double" column="SALDO" />
<property name="dataUtworzenia" type="java.util.Date"
column="DATAUTWORZENIA" />
<joined-subclass name="pl.example.KontoROR" >
<key column="KONTO_ROR_ID" />
<property name="dostep" type="java.lang.String"
column="DOSTEP" />
</joined-subclass>
<joined-subclass name="pl.example.KontoOszczednosciowe" >
<key column="KONTO_OSZCZ_ID" />
<property name="procent" type="double"
column="PROCENT" />
</joined-subclass>
</class>
</hibernate-mapping>
Tabela na subklasę

Podobne dokumenty