Tworzenie warstwy integracji i uzupełnienie wartwy prezentacji w
wielowarstwowej aplikacji
Przykład w środowisku Visual Web JSP
Autor
Zofia Kruczkiewicz
Programowanie i wdrażanie systemów
informatycznych
Architektura aplikacji pięciowarstwowej
ApplicationBean1 Wzorzec fasady usług
SessionBean1 Wzorzec fasady sesji
Page1 (JSF) Page1 (JSF) Page1 (JSF)
Klient1 Klient2 Klient3
Baza danych katalog
Obiektowy model danych Wzorce:
fasady TAplikacja fabryki obiektów strategii
Warstwa integrująca (EntityManager,…) Technologia TopLink Wzorce:
„Domain Store”
„Transfer Object”
fasady (XXXController) fabryki obiektów
SessionBean1 Wzorzec fasady sesji
SessionBean1 Wzorzec fasady sesji
1. Tworzenie pustej bazy danych w
systemie baz danych Derby
Tworzenie bazy danych w systemie baz danych Derby
• Należy wybrać katalog na pustą bazę danych w systemie bazy danych Derby – domyślnym katalogiem jest katalog użytkowników systemu Windows
\.netbeans-derby - slajd(1)
• Należy wybrać z zakładki Services środowiska NetBeans 6.7.1 opcję
Databases. Następnie kliknąć prawym klawiszem myszy na Java DB i wybrać opcję Create Database( slajd (2)
• W formularzu tworzenia bazy danych wg wzoru podanego na slajdzie (3)
wprowadzić dane dotyczące bazy danych: Database Name, User, Password oraz Database Location (domyślne lub wybrane przez użytkownika) – w
wybranym katalogu pojawi się katalog o nazwie bazy danych z pustą bazą danych (slajd (4))
• W zakładce Service należy otworzyć opcję Databases (slajd (5)) i wybierając prawym klawiszem myszy pozycję z listy połączeń do baz danych typu
jdbc:derby://localhost:1527/nazwa_bazy_danych:[użytkownik on
schematbazydanych], należy nacisnąć Connect. Po chwili nastąpi połączenie z bazą danych – pustą – symboliczny kwadrat z lewej strony łańcucha
połączenia ulegnie scaleniu. Przy połączeniu domyślnie zapamiętane jest hasło do bazy danych. Można to zmienić w okienku Properties (wybór po kliknięciu prawym klawiszem myszy na pozycję połączenia)
• Należy kliknąć na symbol [+] z lewej strony łańcucha połączenia – pojawi się zawartość katalogu z trzema pustymi podkatalogami: Tables, Views,
Procedures (slajd (6))
1.1.Zakładanie nowej bazy danych w domyślnym katalogu dla baz danych
typu Derby (1)
Zakładanie pustej bazy danych dla systemu baz danych Derby (2)
Zakładanie bazy danych katalog w systemie baz danych Derby (3)
Założono nową bazę danych katalog w domyślnym
katalogu dla baz danych typu Derby (4)
1.2. Łączenie z pustą bazą danych (5)
Połączenie z pustą bazą danych (6)
2. Wykonanie kontrolerów wartwy
integrującej warstwę biznesową
z bazą danych (warstwa zasobów)
2.1. Dodanie modułu do utrwalania danych
• Należy wstawić moduł typu Persistence Unit - prawym klawiszem kliknąć na nazwę projektu w zakładce Projects, wybrać New\
Persistence Unit (slajd 7). Jeśli w liście nie ma pozycji Persistence Unit, należy wybrać pozycję Other, wybrać w formularzu New File w lewym oknie Categories pozycję Persistence i w prawym oknie
FileTypes typ pliku Persistence Unit.
• Po naciśnięciu Next należy ustalić nazwę modułu. Nazwa modułu wynika z nazwy projektu z przyrostkiem PU. Można zmienić tę nazwę.
Należy wybrać Persistence Library typu TopLink oraz połączyć się z pustą bazą danych założoną w pierwszym etapie prac wybierając
właściwy łańcuch połączenia z listy Data Source (slajd 8).
• W formularzu tworzenia modułu należy wybrać Strategy Generation Table typu Create (slajd 9) – jeśli tabel nie ma, zostaną utworzone, w przeciwnym wypadku nie będą tworzone nowe tabele (sytuacja
sygnalizowana wyjątkami). W katalogu projektu Source Packages – META-INF pojawia się plik persitence.xml i w katalogu Libraries
pojawiają się biblioteki technologii TopLink w plikach jar – zaznaczono je
na slajdzie (10)
Wstawianie do projektu typu Java Application modułu typu Persistence Unit (7)
Wybór bazy danych, w której będą utrwalane obiekty – pustej (8)
Tworzenie modułu utrwalania danych dla technologii TopLink (9)
Plik persistence.xml reprezentujący moduł utrwalania danych typu TopLink Uzupełnianie zawartości projektu typu Java Application o klasy typu
Controller dla każdej z utrwalanych klas modelu obiektowego (10)
2.2. Wprowadzanie warstwy integracji i przekształcanie klas modelu obiektowego na encje
• Na slajdach 11 do 17 podano wskazówki dotyczące zamiany klas TTytul_ksiazki, TTytul_ksiazki_na_kasecie, TEgzemplarz,
TEgzemplarz_termin na klasy z adnotacjami @Entity. W klasie TEgzemplarz wprowadzono wirtualne metody: public Date
getTermin() i public void setTermin(Date termin). Podczas tworzenia kodu należy uzupełniać import pakietów za pomocą opcji Fix Imports (prawym klawiszem myszy należy klikać na ciało klasy i wybrać z
wyskakującego menu Fix Imports i wybierać klasy z pakietu javax.persistence).
• Zgodnie ze slajdem 18, należy w zakładce Projects wybrać w projekcie zakładkę META-INF i otworzyć plik persistence.xml w trybie Design.
W formularzu pliku XML należy za pomocą klawisza Add class wstawić z listy utworzone cztery klasy typu Entity.
• Należy skompilować uzupełniany projekt – tutaj Wypozyczalnia1app
(11) Encja TTytul_ksiazki - zmiana typu klas danych na typ @Entity – dodano adnotacje, nowe atrybuty (Id, Ksiazka) z metodami. Należy zestandaryzować nazwy metod dostępu do składowych
(12) Encja TTytul_ksiazki cd.
(13) Encja TTytul_ksiazki cd. – należy przedefiniować metody equals oraz
hashCode
(14) Encja TTytul_ksiazki_na_kasecie - zmiana typu klas danych na typ @Entity – dzięki polimorfizmowi metod getAktor i setAktor obie klasy zostaną odwzorowane do jednej tabeli TTytul_ksiazki w bazie danych
(15) Encja TEgzemplarz - Zmiana typu klas danych na typ @Entity () – dodano adnotacje, nowy atrybut (Id) z metodami. Należy zestandaryzować nazwy metod dostępu do składowych utrwalanych
(16) Encja Tegzemplarz cd – należy przedefiniować metody equals oraz hashCode
(17) Encja Tegzemplarz_termin - zmiana typu klas danych na typ @Entity – dzięki polimorfizmowi metod getTermin i setTermin obie klasy zostaną odwzorowane do jednej tabeli o nazwie
TEgzemplarz w bazie danych
(18) Wstawienie do modułu typu Persistence Unit wszystkich klas typu Entity
2.3. Dodanie kontrolerów do utrwalania encji
• Na slajdzie (19) pokazano docelową zawartość projektu typu Java Application – należy teraz utworzyć klasy typu Controller dla każdej z utrwalanych klas. W przypadku
dziedziczenia należy utworzyć te klasy dla klas bazowych. Klasy typu Controller są fasadami warstwy integracji dla każdej z utrwalanych klas.
• W celu utworzenia każdego z plików TTytul_ksiazkiController.java oraz
TEgzemplarzController.java, należy prawym klawiszem kliknąć na nazwę projektu w zakładce Projects, wybrać New\Java Class. Jeśli w liście nie ma pozycji Java Class, należy wybrać pozycję Other, wybrać w formularzu New File w lewym oknie
Categories pozycję Java i w prawym oknie FileTypes typ pliku Java Class. Po naciśnięciu Next należy podać nazwę pliku w pozycji Class Name
(TTytul_ksiazkiController) i wybrać z listy Package pakiet, w którym znajdują się klasy warstwy biznesowej (TTytul_ksiazki.java itd..) np. wypozyczalnia1app. Nacisnąć Finish.
Całą procedurę powtórzyć do utworzenia pliku TEgzemplarzController.java. Po zakończeniu tych czynności powstają pliki zawierające klasy typu public z pustym ciałem.
• Na slajdach 20-22 pokazano przebieg tworzenia kodu dla klasy typu Controller dla TTytul_ksiazki. Należy napisać taki kod zgodnie ze wskazówkami również dla klasy TEgzemplarz. Podczas pisania metody getEntityManager() łańcuch w liście parametrów metody createEntityManagerFactory powinien być nazwą modułu Persistence Unit. Oba pliki mogą znajdować się w katalogu klas modelu biznesowego lub nowym pakiecie tego projektu. W celu ułatwienia czynności po zakończeniu
tworzenia ciała klasy TTytul_ksiazkiController można skopiować je i wkleić do ciała klasy TEgzemplarzController, zamienić ciąg znaków TTytul_ksiazki na TEgzemplarz za pomocą CTRL+H. Podczas tworzenia kodu należy uzupełniać import pakietów za pomocą opcji Fix Imports (prawym klawiszem myszy należy klikać na ciało klasy i wybrać z wyskakującego menu Fix Imports i wybierać klasy z pakietu
javax.persistence. Dla typu List wybrać pakiet java.util.).
(19) Inżynieria odwrotna dla utworzonych przez programistę klas typu Controller dla
każdej z utrwalanych klas modelu obiektowego (TTytul_ksiazki)
(20) Diagram klas – uproszczony schemat warstwy integracji
Fasady
warstwy
integracji
(21) Klasa typu TTytul_ksiazkiController dla każdej z klas utrwalanych obiektów
public class TTytul_ksiazkiController { private EntityManagerFactory emf=null;
private EntityManager getEntityManager() { if (emf == null) {
emf = Persistence.createEntityManagerFactory("Wypozyczalnia1appPU"); } return emf.createEntityManager();
}
public boolean findTTytul_ksiazkis(TTytul_ksiazki TTytul_ksiazki) { EntityManager em = getEntityManager();
try {
return em.find(TTytul_ksiazki.class, TTytul_ksiazki.getId())!=null;
} finally { em.close(); } }
public TTytul_ksiazki[] getTTytul_ksiazkis()
{ return (TTytul_ksiazki[]) getTTytul_ksiazki().toArray( new TTytul_ksiazki[0]); } public List<TTytul_ksiazki> getTTytul_ksiazki()
{ EntityManager em = getEntityManager();
try {
javax.persistence.Query q =
em.createQuery("select c from TTytul_ksiazki as c");
return q.getResultList();
} finally { em.close();
} }
public boolean addTTytul_ksiazkis( TTytul_ksiazki TTytul_ksiazki) { EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
em.persist(TTytul_ksiazki);
em.getTransaction().commit();
} finally { em.close();
return false; } }
public boolean addTTytul_ksiazki(ArrayList<TTytul_ksiazki> tytuly) { EntityManager em = getEntityManager();
try {
Iterator it = tytuly.iterator();
while (it.hasNext()) {
TTytul_ksiazki newTTytul_ksiazki = (TTytul_ksiazki) it.next();
if (newTTytul_ksiazki.getId()==null) { em.getTransaction().begin();
em.persist(newTTytul_ksiazki);
em.getTransaction().commit();}
}
} finally { em.close();
return false; } }
public boolean removeTTytul_ksiazkis(TTytul_ksiazki TTytul_ksiazki) { EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
TTytul_ksiazki TTytul_ksiazkix = em.find(TTytul_ksiazki.class, Tytul_ksiazki.getId());
em.remove(TTytul_ksiazkix);
em.getTransaction().commit();
} finally {
em.close();
return false; } }
public boolean updateTTytul_ksiazkis(TTytul_ksiazki TTytul_ksiazki) { EntityManager em = getEntityManager();
try
{ em.getTransaction().begin();
TTytul_ksiazki TTytul_ksiazkix = em.find(TTytul_ksiazki.class, TTytul_ksiazki.getId());
TTytul_ksiazkix.setTytul(TTytul_ksiazki.getTytul());
TTytul_ksiazkix.setAutor(TTytul_ksiazki.getAutor());
TTytul_ksiazkix.setISBN(TTytul_ksiazki.getISBN());
TTytul_ksiazkix.setWydawnictwo(TTytul_ksiazki.getWydawnictwo());
em.getTransaction().commit();
} finally {
em.close();
return false; } }
(22) Klasa typu TEgzemplarzController dla każdej z klas utrwalanych obiektów public class TEgzemplarzController {
private EntityManagerFactory emf = null;
private EntityManager getEntityManager() { if (emf == null) {
emf = Persistence.createEntityManagerFactory("Wypozyczalnia1appPU"); } return emf.createEntityManager();
}
public boolean findTEgzemplarzs(TEgzemplarz TEgzemplarz) { EntityManager em = getEntityManager();
try {
return em.find(TEgzemplarz.class, TEgzemplarz.getId())!=null;
} finally { em.close(); } }
public TEgzemplarz[] getTEgzemplarzs() {
return (TEgzemplarz[]) getTEgzemplarze().toArray(new TEgzemplarz[0]); } public List<TEgzemplarz> getTEgzemplarze() {
EntityManager em = getEntityManager();
try {
javax.persistence.Query q = em.createQuery("select c from TEgzemplarz as c");
return q.getResultList();
} finally {
em.close(); } }
public boolean addTEgzemplarzs(TEgzemplarz TEgzemplarz) { EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
em.persist(TEgzemplarz);
em.getTransaction().commit();
} finally { em.close();
return false; } }
public boolean addTEgzemplarze(ArrayList<TTytul_ksiazki> tytuly) { EntityManager em = getEntityManager();
Iterator it = tytuly.iterator();
try {
while (it.hasNext()) {
TTytul_ksiazki newTTytul_ksiazki = (TTytul_ksiazki) it.next();
if (newTTytul_ksiazki.getId()==null) continue;
terator it_ = newTTytul_ksiazki.getMKsiazka().iterator();
while (it_.hasNext()) {
TEgzemplarz newTEgzemplarz = (TEgzemplarz) it_.next();
if (newTEgzemplarz.getId()==null) { em.getTransaction().begin();
em.persist(newTEgzemplarz);
em.getTransaction().commit(); } }
} } finally {
em.close();
return false; } }
public boolean removeTEgzemplarzs(TEgzemplarz TEgzemplarz) { EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
TEgzemplarz TEgzemplarzx = em.find(TEgzemplarz.class, TEgzemplarz.getId());
em.remove(TEgzemplarzx);
em.getTransaction().commit();
} finally { em.close();
return false;
} }
public boolean updateTEgzemplarzs(TEgzemplarz TEgzemplarz) { EntityManager em = getEntityManager();
try {
em.getTransaction().begin();
TEgzemplarz TEgzemplarzx = em.find(TEgzemplarz.class, TEgzemplarz.getId());
TEgzemplarzx.setNumer(TEgzemplarz.getNumer());
em.getTransaction().commit();
} finally { em.close();
return false;
} } }
3. Wykonanie formularzy typy JSP zawierających wieloużywalne
formularze typu JSPF dla –
uzupełnienie formularzy dla warstwy
integrującej
Projekty formularza głównego „Strona główna” (Page1.jsp)
Projekty formularza „Dodaj tytul do bazy” (Baza_tytul.jsp)
Wstawianie atrybutów
obiektowych do kodu Javy w celu zmiany właściwości komponentu
metodami
programistycznymi - należy to wykonać dla uproszczenia dla każdego
komponentu
użytego w projekcie.
Projekty formularza „Przepisz tytuły do bazy” (Baza_tytuly.jsp)
Projekty formularza „Przepisz ksiazki do bazy” (Baza_ksiazki.jsp)
4. Wykonanie oprogramowania systemu dla wielu klientów ze wspólną
warstwą biznesową istniejącą podczas sesji i wspólną warstwą
integrująca z bazą danych – uzupełnienie dla warstwy
integrującej
4.1. Oprogramowanie dotyczące formularza „ Dodaj tytul do bazy”
4.1.1. Definicje metod w klasie Baza_tytul dla strony typu JSP – do zapisu tytułów z warstwy biznesowej metodą zapisz_tytul_do_bazy (obsługa zdarzenia bazatytul_action)
4.1.2. Generowania widoku w fazie Response - przetwarzanie strony metoda prerender
(wygaszanie linku do bieżącej strony w formularzu Menu typu JSPF, aktualizacja tablicy tytuly metodą updateTytuls w klasie ApplicationBean1, wyświetlanej w komponencie Table strony Tytulybaza typu JSPF, czyszczenie pól formularza FormTytul typu JSPF jego metodą
odswiez_form)
4.1.3. Definicje metod w klasie ApplicationBean1:
- odczytującą dane typu kolekcja obiektów TTytul_ksiazki i TTytul_ksiazki_na_kasecie z bazy danych (updateTytuls)
- metoda zapisz_tytul_do_bazy zapisująca do bazy danych (addTTytul_ksiazkis) i warstwy biznesowej (dodaj_tytul ) pojedynczych danych typu TTytul_ksiazki i TTytul_ksiazki_na_kasecie oraz odświeżająca zawartość komponentu typu DropDownList na stronie Tytulyaplikacja typu JSPF (przygotujtytuly)
4.1.4. „Bindowanie” tablicy tytuly z komponentem typu Table w celu
wyświetlenia wszystkich tytułów przechowywanych w pamięci aplikacji
4.2. Oprogramowanie dotyczące formularza Baza_tytuly.jsp
4.2.1. Definicje metod w klasie Baza_tytuly dla strony typu JSP – do zapisu tytułów z warstwy biznesowej metodą zapisz_tytuly_do_bazy (obsługa zdarzenia dodajtytulbaza_action)
4.2.2. Generowanie widoku w fazie Response - przetwarzanie strony metodą prerender
(wygaszanie linku do bieżącej strony w fdormularzu Menu typu JSPF i aktualizacja tablicy tytuly metodą updateTytuls w klasie ApplicationBean1 wyświetlanej w komponencie Table strony Tytulybaza typu JSPF)
4.2.3. Definicje metody zapisz_tytuly_do_bazy w klasie ApplicationBean1 związanej z zapisem danych typu kolekcja obiektów TTytul_ksiazki i TTytul_ksiazki_na_kasecie w bazie danych
4.3. Oprogramowanie dotyczące formularza Baza_ksiazki.jsp
4.3.1. Definicje metod w klasie Baza_ksiazki dla strony typu JSP – do zapisu książek z warstwy biznesowej metodą zapisz_ksiazki_do_bazy (obsługa zdarzenia dodajksiazkabaza_action) 4.3.2. Generowanie widoku w fazie Response - przetwarzanie strony metodą prerender
(wygaszanie linku do bieżącej strony w formularzu Menu typu JSPF i aktualizacja tablicy ksiazki metodą updateKsiazkis w klasie ApplicationBean1 wyświetlanej w komponencie Table strony Ksiazkibaza typu JSPF)
4.3.3. Definicja metod w klasie ApplicationBean1 związanej z zapisem (zapisz_ksiazki_do_bazy) 4.3.4. Definicja metod w klasie ApplicationBean1 związanej z odczytem (updateKsiazkis) danych typu kolekcja obiektów TEgzemplarz i TEgzemplarz_termin w bazie danych
4.3.5. „Bindowanie” tablicy ksiazki z komponentem typu Table w celu
wyświetlenia wszystkich książek przechowywanych w pamięci aplikacji
4.4.
4.5. Widok bazy danych w zakładce Services – wykonanie operacji ViewData dostępnej z wyskakującego menu po naciśnięciu tabeli TEgzemplarz prawym
klawiszem myszy
Dodatek: Zalecenia dla klas typu Entity, które mogą być utrwalane w bazach danych (1)
opis klas Entity na podstawie: http://java.sun.com/javaee/5/docs/tutorial/doc/
• Musi posiadać adnotację javax.persistence.Entity (@Entity)
• Klasa musi mieć konstruktor typu public lub protected, bezparametrowy
• Klasa nie może być typu final
• Klasa musi być serializowana, stąd musi wystąpić w deklaracji klasy implements Serializable
• Klasy typu Entity mogą dziedziczyć po klasach zarówno typu Entity jak i zwykłej oraz zwykła klasa może dziedziczyć od klasy typu Entity.
• Dostęp do danych obiektu typu Entity może odbywać się tylko poprzez metody
• Musi mieć metody hashCode() i equals(Object other)
• Podstawowe adnotacje dla kluczy głównych (PK)
@Id oznacza adnotację dla klucza głównego.
Adnotacja @GeneratedValue (strategy=GenerationType.<...>) oznacza strategię tworzenia wartości kluczy głównych, zależną od systemu baz danych
(javax.persistence.GeneratedValue, javax.persistence.GenerationType).
Adnotacja @GeneratedValue(strategy = GenerationType.IDENTITY) oznacza odpowiedzialność za generowanie wartości kluczy głównych przez bazę danych.
Adnotacja @GeneratedValue(strategy = GenerationType.AUTO) pozwala na przejęcie odpowiedzialności za generowanie kluczy przez system mapujący np.TopLink, który
posługuje się pomocniczą tabelą przechowującą wartości potrzebne do generowania kluczy)
Dodatek: Zalecenia dla klas typu Entity, które mogą być utrwalane w bazach danych (2)
• Typy danych pól: typy nieobiektowe, java.lang.String, java.math.BigInteger,
java.math.BigDecimal,java.util.Date, java.util.Calendar, java.sql.Date, java.sql.Time, java.sql.TimeStamp, user-defined serializable types, byte[], Byte[], char[],
Character[], typu wyliczeniowe, kolekcje, klasy wewnętrzne
• Pomijanie pól przy utrwalaniu realizuje się za pomocą javax.persistence.Transient -
@Transient
• Można stosować następujące interfejsy kolekcji: java.util.Collection, java.util.Set, java.util.List, java.util.Map oraz korzystać z parametryzacji kolekcji np.
set<PhoneNumber> getPhoneNumbers() {}
void setPhoneNumbers(Set<PhoneNumber>) {}
• Klucze główne: typy nieobiektowe (adnotacja @Id - javax.persistence.Id ), typy złożone: java.lang.String, java.util.Date, java.sql.Date – adnotacje
javax.persistence.EmbeddedId and javax.persistence.IdClass (@EmbeddedId oraz
@IdClass)
– Muszą być publiczne
– Klasa klucza głównego musi mieć domyślny konstruktor,
– Klasa głównego klucza musi mieć metody hashCode() and equals(Object other) – Klasa głównego klucza musi być serializowana
•
Dodatek: Zalecenia dla klas typu Entity, które mogą być utrwalane w bazach danych (3)
Zaznaczone metody w przykładowej klasie muszą wystąpić w klasach kluczy głównych oraz w klasach typu Entity
public final class LineItemKey implements Serializable { public Integer orderId;
public int itemId;
public LineItemKey() {}
public LineItemKey(Integer orderId, int itemId)
{ this.orderId = orderId; this.itemId = itemId; } public boolean equals(Object otherOb)
{ if (this == otherOb) { return true; }
if (!(otherOb instanceof LineItemKey)) { return false; } LineItemKey other = (LineItemKey) otherOb;
return ( (orderId == null ? other.orderId==null :
orderId.equals (other.orderId) ) && (itemId == other.itemId) ); } public int hashCode()
{ return ( (orderId==null ? 0 : orderId.hashCode()) ^ ((int) itemId) ); } public String toString()
{ return "" + orderId + "-" + itemId; } }
Dodatek: Zalecenia dla klas typu Entity, które mogą być utrwalane w bazach danych (4)
• Typy relacji (liczność)
– One-to-one: adnotacja javax.persistence.OneToOne -@OneToOne
– One-to-many: adnotacja javax.persistence.OneToMany - @OneToMany – Many-to-one: adnotacja javax.persistence.ManyToOne - @ManyToOne
– Many-to-many: adnotacja javax.persistence.ManyToMany - @ManyToMany
• Kierunek relacji
– Jednokierunkowa – posiada implementację po jednej stronie relacji (zapytanie może być realizowane od właściela, który zna inny obiekt )
– Dwukierunkowa musi spełniać wymagania:
• Przeciwna strona relacji musi posiadać element typu mappedBy o adnotacji
@OneToOne, @OneToMany, lub @ManyToMany, w zależności od definicji drugiej strony relacji. Element mappedBy oznacza pole właściciela relacji (drugiej strony relacji).
• Druga strona relacji many-to-many lub many-to-one nie może posiadać elementu mappedBy.
• Dla relacji one-to-one, strona właściciela odpowiada stronie z kluczem obcym.
• Dla relacji many-to-many każda strona relacji jest właścicielem drugiej strony
.
• Zapytanie mogą być realizowane w obu kierunkach
• Kaskadowe usuwanie wszystkich obiektów powiązanych przez element
mappedBy np.
@OneToMany(cascade=REMOVE, mappedBy="customer ") public Set<Order> getOrders() { return orders; }