niedziela, 23 listopada 2008

Odwzorowanie dziedziczenia przykład

Na początek diagram:


Jak widać mamy tu dziedziczenie, relację wiele do wiele jak i asocjację skierowaną.

Schemat takiej bazy danych może wyglądać następująco:

create table works (

id NUMBER not null primary key,

tempo NUMBER,

genre VARCHAR2(255),

peges NUMBER(4),

title VARCHAR2(255)

);

create table author_work (

author_id NUMBER not null,

work_id NUMBER not null,

primary key (work_id, author_id)

);

create table authors (

id NUMBER not null primary key,

alias VARCHAR2(255)

);

create table persons (

id NUMBER not null primary key,

name VARCHAR2(255)

);

alter table authors

add constraint authorsFK0 foreign key (id) references persons;

alter table author_work

add constraint author_workFK0 foreign key (author_id) references authors;

alter table author_work

add constraint author_workFK1 foreign key (work_id) references works;

Czyli został zastosowany drugi schemat odwzorowania dziedziczenia klas na tabele, mianowicie tabela na każdą hierarchie klas. Z trzech klas (Work, Song, Book) powstała jedna tabela works.

Problem asocjacji wiele do wiele został rozwikłany dodaniem tabeli łączącej autor_work. Ale teraz najważniejsza część: jak Hibernate wygenerował klasy oraz pliki mapujące na podstawie tego schematu bazy.

Klasa Works:

public class Works implements java.io.Serializable {


private BigDecimal id;

private BigDecimal tempo;

private String genre;

private Short peges;

private String title;

private Set authorses = new HashSet(0);

….

//konstruktory, settery , gettery

}

Klasa Authors:

public class Authors implements java.io.Serializable {


private BigDecimal id;

private Persons persons;

private String alias;

private Set workses = new HashSet(0);

}

Klasa Persons

public class Persons implements java.io.Serializable {


private BigDecimal id;

private String name;

private Set authorses = new HashSet(0);

}

Nic tu zaskakującego na razie nie ma poza tym, że nie została zaimplementowana Klasa AuthorWork na podstawie tabeli author_work. Jak więc Hibernate poradzi sobie z zapisem danych do odpowiednich tabel? Otóż właśnie po to zostały utworzone tak zwane pliki mapujące. Warto się im dokładnie przyjrzeć. Niestety umieszczenie tych kodów w całości jest bardzo nieczytelne postaram się opisać ich fragmenty.

Plik Works.hbm.xml
- Zdefiniowanie nazwy (name) klasy oraz nazwy tabeli (table)

<class name="przykad1.Works" table="WORKS">


- Klucz wygenerowany przez aplikację. Stworzone jest specjalne pole dla klucza <id> posiada ono takie atrybuty: nazwę(name), czyli jak będzie nazwane to pole w klasie oraz typ(type). W znacznik column określane są własności kolumny tej tabeli . Dodatkowo dołączona jest informacja w jaki sposób ma być generowany klucz. Podstawowe generatory to: native, identity, sequence, assigned.

<id name="id" type="big_decimal">
<column name="ID" precision="22" scale="0" />
<generator class="assigned" />
</id>


- Aby opisać całą tabelę trzeba zdeklarować wszystkie kolumny w tabeli połączone z odpowiednimi polami w klasie, oczywiście trzeba jeszcze określić typy.

<property name="tempo" type="big_decimal">
<column name="TEMPO" precision="22" scale="0" />
</property>


- Element <set> informuje, że dane pole jest typu java.util.Set. W tym przykładzie ma ono nazwę authorses. Ponieważ wystąpiła tu relacja wiele do wielu, wymaga to utworzenia dodatkowej tabeli łączącej, dlatego została określona nazwa tej tabeli AUTHOR_WORK.

<set name="authorses" inverse="false" table="AUTHOR_WORK">
<key>
<column name="WORK_ID" precision="22" scale="0" not-null="true" />
</key>
<many-to-many entity-name="przykad1.Authors">
<column name="AUTHOR_ID" precision="22" scale="0" not-null="true" />
</many-to-many>
</set>


Inne pliki zostały odwzorowane według podobnych schematów. Może jeszcze jeden przykład tym razem relacji jeden do wiele.

Plik: Persons.hmb.xml

<set name="authorses" inverse="true">
<key>
<column name="ID" precision="22" scale="0" not-null="true" unique="true" />
</key>
<one-to-many class="przykad1.Authors" />
</set>

Oraz odzwierciedlenie tej relacji wpliku Authors.hmb.xml

<many-to-one name="persons" class="przykad1.Persons" update="false" insert="false" fetch="select">
<column name="ID" precision="22" scale="0" not-null="true" unique="true" />
</many-to-one>




Odwzorowanie dziedziczenia, asocjacji i kompozycji w bazie


Cel: Stworzenie efektywnego modelu obiektowego przy pomocy Hibernate: dziedziczenie, asocjacja, kompozycja. Wybór strategii odzwierciedlenia dziedziczenia w bazie danych.

Trochę inna strona Hibernate. Do tej pory praca z Hibernate wyglądała następująco: po prawidłowym skonfigurowaniu połączenia z bazą danych należało stworzyć model obiektowy baz danych, a następnie przy pomocy plików mapujących można było wygenerować schemat bazy danych. Jest to tak zwane "podejście z góry w dół".

W NetBeans 6.5 zostało dodane narzędzie, które umożliwia odwrotny scenariusz odwzorowywania, czyli na początku tworzony jest schemat bazy danych, a następnie przy pomocy narzędzi Hibernate zostają wygenerowane klasy Javy oraz pliki odwzorowań. Tak zwane "podejście z dołu do góry".

Jednak problemy odwzorowania relacyjno obiektowego nie znikają. Schemat obiektowy posiada wiele takich własności, których nie można bezpośrednio przełożyć na schemat relacyjny. Problem pojawia się w momencie gdy chcemy odzwierciedlić dziedziczenie, asocjacje czy kompozycję.

1. Dziedziczenie

Istnieją trzy różne podejścia stosowane do odwzorowania dziedziczenia:

1.1. Tabela na każdą klasę konkretną – dokładnie jedna tabela na każdą nieabstrakcyjną klasę, wszystkie własności klasy nadrzędnej są dopisywane do klas dziedziczącej.

WADA: Zapytanie dotyczące klasy bazowej musi zostać rozbite na wiele poleceń SELECT, często jest to mało wydajne.

Wygląda to tak:


1.2. Tabela na każdą hierarchie klas – czyli całą hierarchia klas odwzorowywana jest w jednej tabeli. Dodatkowo dodawana jest kolumna dyskryminatora typu.

WADA: Nie można nadać ograniczenia Not null dla kolumn które są właściwościami podklasy.

1.3. Tabela na każdą podklasę – czyli każda klasa jest reprezentowana jako jedna tabela w bazie i podklasy są w asocjacji z klasą nadrzędną.

WADA: Złożone zapytania.


Wszystkie te modele mają swoje wady i zalety tak więc należy stosować strategię odpowiednią do konkretnego schematu.


Tu omówiony został przykład:
Odwzorowanie dziedziczenia przykład
http://agatkiwoj.blogspot.com/2008/11/odwzrowanie-dziedziczenia-przykad.html

sobota, 22 listopada 2008

Połączenie Hiberante z Oraclem

1. Opis konfiguracji
Wszystkie ustawienia jakie będą opisane poniżej należy dokonać w pliku właściwości Javy o nazwie hibernate.properties lub w pliku XML o nazwie hibernate.cfg.xml co zostanie dokładniej opisane w kolejnym punkcie. Pliki te różnią się formą zapisu jednak opisy danych, które mają znaleźć się w obu plikach są takie same. Większość źródeł wiedzy o Hibernate jak i sama dokumentacja zalecają konfigurację Hibernate przy pomocy meta danych.
Plik konfiguracyjny składają się z listy pól właściwości. Większość właściwości przyjmuje odpowiednie wartości i nie ma potrzeby ich konfigurować. Jednak niektóre własności musimy koniecznie skonfigurować należą do nich:
  • hibernate.connection.driver_class – czyli klasa sterownika JDBC. Aby skorzystać z Framework Hibernate należy dołączyć do projektu bibliotekę (JAR) sterownika JDBC, który należy dopasować do konkretnej relacyjnej bazy danych. Sterownik ten należy pobrać ze strony bazy danych, z którą chcemy połączyć Hibernate.
  • hibernate.dialect - dialekt SQL wykorzystywany przez Hibernate. Ponieważ każda baza danych zachowuje się inaczej utworzono specjalne dialekty Hibernate, które usuwają te różnice. W projekcie należy określić z jakiego dialektu korzystamy w pliku konfiguracyjnym Hiberante. Dialekt definiuje odmianę języka SQL i cechy szczególne bazy danych.
  • hibernate.connection.url – podany przez JDBC adres URL do egzemplarza baz danych.
  • hibernate.connection.username – nazwa użytkownika bazy danych.
  • hibernate.connection.password – hasło do bazy danych.
2. Przykład konfiguracji Hiberante za pomocą meta danych zapisywany jest w projekcie jako plik hibernate.cfg.xml. Prezentowana aplikacja łączy się z bazą Oracle 10g.

<?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.dialect">org.hibernate.dialect.OracleDialect
</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver
</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl
</property>
<property name="hibernate.connection.username">uzytkownik
</property>
<property name="hibernate.connection.password">haslo
</property>
<mapping resource="paczka/nazwaKlasy.hbm.xml" />
</session-factory>
</hibernate-configuration>

Przy pomocy znacznika <property> można określić właściwości połączenia z bazą danych. Znacznik &l;tmapping&p; służy do konfiguracji odwzorowań.

Źródła: Hiberante od Nowicjusza do Profesjonalisty, Dave Minter, Jeff Linwood

piątek, 21 listopada 2008

Hibernate + NetBeans 6.5 krok po kroku

Przykład stworzony jest przy pomocy NetBeans 6.5 oraz technologii Hibernate 3.5. Baza danych to Oracle 10g.

1. Tworzymy nowy projekt Ctrl+Shift+N z kategorii Java - > Java Aplication następnie Next. Wpisujemy nazwę projektu Przykład1 oraz wybieramy ścieżkę docelową, gdzie zostanie utworzony projekt. A następnie przycisk Finish.

2. Jeśli jeszcze nie mamy wcześniej zainstalowanego Hibernate można to zrobić przy pomocy Tools -> Plugins a następnie wybrać Hibernate Support oraz Hibernate 3.2.5 Library i Install.

3. Skoro już mamy zainstalowane biblioteki Hibernate powinniśmy je jeszcze dołączyć do naszego projektu. W panelu Projects zaznaczamyLibraries, potem kolejno Add Library.

4. Tworzymy plik konfiguracyjny Hibernate , który powinien się nazywać hibernate.cfg.xml. Wybieramy New -> XML Document i nadajemy mu nazwę hibernate.cfg i Next, Finish.

I uzupełniamy odpowiednim kodem, przykład pliku konfiguracyjnego:

<?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.dialect">org.hibernate.dialect.OracleDialect
</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver
</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl
</property>
<property name="hibernate.connection.username">uzytkownik
</property>
<property name="hibernate.connection.password">haslo
</property>
</session-factory>
</hibernate-configuration>


Więcej o konfiguracji połączenia w artykule Połączenie Hibernate z Oraclem.

5. Kolejną ważną rzeczą jest dodanie sterownika do odpowiedniej bazy danych z którą chcemy połączyć aplikację tzn JDBC Driver.

Można je pobrać dla Oracle ze strony: http://www.oracle.com/technology/software/tech/java/sqlj_jdbc/index.html

Dodajemy to następująco Libraries ->Properties -> Add JAR/Folder wybieramy odpowiednie archiwum JAR Open i Ok.

6. A teraz coś czego nie można było tworzyć we wcześniejszej wersji Hibernate, czyli generowanie kodu na podstawie istniejących tabel w bazie danych.

Aby móc skorzystać z tej opcji musimy najpierw w połączonej z Hibernate bazie danych stworzyć tabele. Dla zademonstrowanie tego przykładu utworzyłam taką tabelę w Oraclu:

CREATE TABLE Osoba

( imie VARCHAR2(15) NOT NULL,

nazwisko VARCHAR2(15) NOT NULL,

plec VARCHAR2(1) CHECK(plec IN ('M','D')),

pesel VARCHAR2(11) PRIMARY KEY

);

Używamy Crlt+N wybieramy Categories: Hibernate i File Types: Hibernate Mapping Files and POJOs from Database.

Next.

Nadajemy nazwę pliku generateCode i dajemy Next. Pojawia się okno z nazwą bazy, należy podać hasło i OK. W oknie Available Tables pojawią się wszystkie tabele, które są utworzone w bazie danych, można dodać tylko część z nich do projektu przyciskiem Add. Bądź dodać całą bazę używając przycisku Add All. Next.

Domyśle ustawienia sprawiają, że zostaną utworzone klasy Javy oraz pliki mapujące Hibernate , tak więc nic nie należy zmieniać, pozostaje przycisk Finish.

Powstała dzięki temu klasa Osoba.java oraz plik mapujący Osoba.hbm.xml oraz plik xml generateCode.xml.

Aby udowodnić, że to naprawdę super narzędzie skopuję wygenerowane pliki

Osoba.java

package przykad1;

public class Osoba implements java.io.Serializable {

private String pesel;

private String imie;

private String nazwisko;

private String plec;

public Osoba() {

}

public Osoba(String pesel, String imie, String nazwisko) {

this.pesel = pesel;

this.imie = imie;

this.nazwisko = nazwisko;

}

public Osoba(String pesel, String imie, String nazwisko, String plec) {

this.pesel = pesel;

this.imie = imie;

this.nazwisko = nazwisko;

this.plec = plec;

}

public String getPesel() {

return this.pesel;

}

public void setPesel(String pesel) {

this.pesel = pesel;

}

public String getImie() {

return this.imie;

}

public void setImie(String imie) {

this.imie = imie;

}

public String getNazwisko() {

return this.nazwisko;

}

public void setNazwisko(String nazwisko) {

this.nazwisko = nazwisko;

}

public String getPlec() {

return this.plec;

}

public void setPlec(String plec) {

this.plec = plec;

}

}

Zostały więc wygenerowane od razu gettery i settery oraz konstruktory klasy.

Plik mapujący wygląda następująco:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<!-- Generated 2008-11-22 01:24:59 by Hibernate Tools 3.2.1.GA -->
<hibernate-mapping>
<class name="przykad1.Osoba" table="OSOBA" schema="AGATA">
<id name="pesel" type="string">
<column name="PESEL" length="11" />
<generator class="assigned" />
</id>
<property name="imie" type="string">
<column name="IMIE" length="15" not-null="true" />
</property>
<property name="nazwisko" type="string">
<column name="NAZWISKO" length="15" not-null="true" />
</property>
<property name="plec" type="string">
<column name="PLEC" length="1" />
</property>
</class>
</hibernate-mapping>
Warto również zajrzeć jak zmienił się plik 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.dialect">org.hibernate.dialect.OracleDialect
</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver
</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@localhost:1521:orcl
</property>
<property name="hibernate.connection.username">uzytkownik
</property>
<property name="hibernate.connection.password">haslo
</property>
<mapping resource="przykad1/Osoba.hbm.xml"/>
</session-factory>
</hibernate-configuration>

Automatycznie został dodany znacznik ze ścieżką do pliku mapującego.