I.
Wprowadzenie do  języków zapytań (1)
II.
Wprowadzenie do  języków zapytań (2)
III.
Pojęcia obiektowości w bazach danych (1)
  Wstęp
  1. Co to jest obiektowość?
  2. Obiekt
  3. Metody związane z obiektem
  4. Obiekt złożony
  5. Relatywizm obiektów
  6. Zasada wewnętrznej identyfikacji
  7. Powiązania pomiędzy obiektami
  8. Hermetyzacja i ukrywanie informacji
  9. Mechanizm komunikatów
  Podsumowanie
  Zadania
IV.
Pojęcia obiektowości w bazach danych (2)
V.
Podstawy semantyczne języków zapytań
VI.
Modele składu obiektów
VII.
Stos środowisk, rezultaty zapytań, funkcja nested
VIII.
Język SBQL (Stack-Based Query Language) (1)
IX.
X.
Dalsze własności SBQL
XI.
Operatory order by i group by
XII.
Przetwarzanie struktur nieregularnych
XIII.
Rozszerzenie języków zapytań o konstrukcje imperatywne
XIV.
Procedury, procedury funkcyjne, metody, reguły zakresu
XV.
Parametry procedur i metod, procedury rekurencyjne, optymalizacja poprzez modyfikację zapytań

 

7. Powiązania pomiędzy obiektami

Dzięki istnieniu unikalnych identyfikatorów obiektów w obiektowych językach programowania i bazach danych możliwe jest tworzenie bezpośrednich powiązań pointerowych prowadzących od jednego obiektu do innego obiektu. Pointer jest daną zawierającą identyfikator obiektu jako swoją wartość. Istnieje wiele terminów na określenie związków semantycznych zachodzących pomiędzy obiektami. Np. w terminologii C++ używa się "pointer" (pointer), zaś w innych językach używa się "referencja" (reference), "powiązanie" (link), "asocjacja" (association), "związek" (relationship) lub przyjmuje się pewną nieprecyzyjną terminologię mówiąc, że wartością danej jest "obiekt" (najczęściej z oczywistą intencją "identyfikator obiektu"). Istnieją warianty znaczeniowo-terminologiczne związane z tym pojęciem, które nie mają znaczenia dla naszych rozważań.

Powiązania są najczęściej realizacją związków (asocjacji) pomiędzy obiektami. Rys.11 ilustruje powiązania pomiędzy obiektami FIRMAPRACOWNIK: dane pointerowe o nazwach Zatrudnia oraz Prezes mają jako wartość identyfikatory obiektów PRACOWNIK, zaś dana pointerowa PracujeW przechowuje identyfikator obiektu FIRMA. Związek "jeden do wielu" jest w tym przypadku zaimplementowany poprzez umieszczenie wewnątrz obiektu FIRMA wielu pointerów Zatrudnia.


Rys.11. Powiązania pointerowe pomiędzy obiektami

Powiązania pointerowe były krytykowane przez propagatorów modelu relacyjnego jako prowadzące do utraty zalety określanej jako "niezależność danych" (czyli niezależność od programów działających na danych i elementów fizycznej reprezentacji danych, np. adresów dyskowych). Systemy relacyjne nie wprowadzają tego rodzaju powiązań; odstępstwa są piętnowane jako wykroczenia przeciwko zasadom. Regułą jest reprezentacja powiązań semantycznych pomiędzy danymi poprzez umieszczanie identycznych wartości w różnych miejscach relacyjnej struktury danych, zwykle wartości klucza głównego (primary) i tzw. klucza obcego (foreign).

Obiektowość wraca do powiązań pointerowych, odrzucając przy tym stare argumenty zwolenników modelu relacyjnego. Argument dotyczący niezależności danych przestaje być istotny, gdy powiązania pointerowe bazują na symbolicznych identyfikatorach obiektów, a nie na fizycznych adresach danych. Zaletą powiązań pointerowych pomiędzy obiektami jest naturalne odwzorowanie semantycznych związków między obiektami oraz konceptualizacja programów, dzięki tzw. wyrażeniom ścieżkowym (path expressions), umożliwiającym skrócenie kodu i zwiększenie jego czytelności. Powiązania pointerowe powodują także zwiększenie szybkości działania, gdyż nawigacja (przejście) wzdłuż pointera, np. od obiektu PRACOWNIK do obiektu FIRMA, jest z reguły bardzo szybka, szczególnie wtedy, gdy pointer daje się bezpośrednio odwzorować na adres dyskowy wskazywanego obiektu. W systemach relacyjnych tego rodzaju przejście wymaga wykonania operacji złączenia (join), co pociąga za sobą konieczność nietrywialnej optymalizacji zapytań, a ta nie zawsze okazuje się skuteczna.

Podkreślaną niekiedy wadą powiązań pointerowych jest zwiększona "sztywność" struktury danych. Zwolennicy modelu relacyjnego uważają, że dane takie jak FIRMAPRACOWNIK powinny być kojarzone w zapytaniach, a nie na poziomie strukturalnych własności danych. Przykładowo, w SQL przejście od pracownika do jego firmy odbywa się poprzez następujące zapytanie (przyjmując istnienie klucza obcego NrFirmy w tablicy PRACOWNIK ):

P3.1.
SQL:

select FIRMA.* from PRACOWNIK, FIRMA
where PRACOWNIK.NrFirmy = FIRMA.NrFirmy
and PRACOWNIK.Nazwisko = 'Nowak'

Występujący w tym zapytaniu warunek PRACOWNIK.NrFirmy = FIRMA.NrFirmy jest koncepcyjnie równoważny przejściu wzdłuż pointera PracujeW w modelu obiektowym. W zapytaniach obiektowego języka zapytań taki warunek się nie pojawi, gdyż jest on "wszyty" w strukturę danych w postaci powiązania pointerowego. Równoważne zapytania SBQL (który będzie podstawą dalszej części tej książki) i OQL (język zapytań standardu ODMG) będą wyglądały następująco:

P3.2. SBQL:

(PRACOWNIK where Nazwisko = "Nowak").
PracujeW . FIRMA


P3.3.
OQL:

select f from PRACOWNIK as p, p.PracujeW as f
where p.Nazwisko = "Nowak"

Taki warunek musi natomiast pojawić się w każdym zapytaniu SQL, które kojarzy pracownika z jego firmą. Zdaniem zwolenników modelu relacyjnego, struktura relacyjna jest bardziej elastyczna od obiektowej, gdyż nie określa a priori, jakie mają być skojarzenia pomiędzy danymi, pozostawiając je na etap formułowania zapytań. W większości jednak przypadków taka elastyczność niewiele daje, gdyż skojarzenia danych są zawarte w ich modelu pojęciowym i programista ma nikłe możliwości i potrzebę wykorzystania innych skojarzeń. Inaczej mówiąc, efektem wyżej wymienionej elastyczności jest prawie wyłącznie zwiększona złożoność zapytań i przedłużenie czasu ich wykonania. Praktyczne zalety zwiększonej elastyczności są iluzoryczne.

Inna potencjalna wada powiązań pointerowych polega na możliwości braku integralności danych wskutek pointerów zawierających identyfikatory nieistniejących już obiektów (tzw. "zwisających" pointerów). Jest to niebezpieczeństwo właściwe dla dowolnej struktury danych, a jego odpowiednik w strukturach relacyjnych pojawia się w postaci braku integralności odwołań (referential integrity).

Niektóre modele (np. ODMG) zakładają, że pointery występują parami: jeżeli istnieje pointer od A do B, to istnieje także bliźniaczy pointer (ewentualnie o innej nazwie) od B do A; patrz pointery PracujeWZatrudnia na Rys.11. W modelu ODMG można również zadeklarować pointery zorientowane, bez bliźniaczego pointera odwrotnego; np. pointer Prezes na Rys.11. Spójność bliźniaczych pointerów musi być podtrzymywana systemowo (poza świadomością programisty), przez co fakt istnienia bliźniaczych pointerów nie ma większego wpływu na opisywaną przez nas semantykę języków zapytań.


Rys.12. Zamiana powiązań ternarnych z atrybutami na obiekty i powiązania binarne

Model oparty na pointerach uwzględnia wyłącznie związki binarne pomiędzy klasami obiektów. W modelu tym nie można również uwzględnić atrybutów związków (i ewentualnie metod przypisanych do związków). Np. dla związku ByłZatrudniony pomiędzy obiektem Osoba i obiektem Firma atrybutami mogą być PoczątekZatrudnieniaKoniecZatrudnienia.

Istnieją kontrowersje co do tego, czy są to istotne ograniczenia modelowania pojęciowego. Potrzeba wprowadzenia związków wyższego rzędu i/lub z atrybutami pojawia się w modelowaniu pojęciowym rzadziej i można je zastąpić związkami binarnymi bez atrybutów poprzez wprowadzenie nowej klasy obiektów. Model, w którym mogą istnieć powiązania n-arne (n 3 3) oraz posiadające atrybuty, powoduje znaczny rozrost środków programistycznych niezbędnych dla jego obsługi. Negatywnym przykładem takiego założenia jest bardzo rozbudowana usługa w zakresie związków (Relationship Service) standardu CORBA. Ponadto, jeżeli istnieją atrybuty związku, to mogą okazać się konieczne (niekoniecznie generyczne) metody dla obsługi tych atrybutów. W tej sytuacji powiązanie musiałoby być związane z własną klasą. Tego rodzaju rozwiązanie występuje w metodyce OMT oraz w notacji UML. Jest ono uzasadnione dla roli, którą wypełniają środki modelowania pojęciowego (które nie muszą mieć - i zwykle nie mają - algorytmicznej precyzji), natomiast wydaje się mniej uzasadnione dla interfejsów programistycznych, gdzie algorytmiczna precyzja jest nieodzowna, zaś konieczność uproszczenia języków zmusza do rezygnacji z cech drugorzędnych i redundantnych. Dla uproszczenia budowanej przez nas semantyki języka zapytań przyjmiemy więc, że powiązania mogą być tylko pointerowe (binarne) tak, jak to przedstawiliśmy na Rys.11.

Jak już zaznaczyliśmy, dowolny n-arny związek (z ewentualnymi atrybutami) można wyeliminować poprzez wprowadzenie nowych obiektów oraz n związków binarnych. Rys.12 ilustruje przekształcenie tą metodą powiązań ternarnych Transakcja z atrybutami Przedmiot, Data i Wartość na nowe obiekty TRANSAKCJA oraz trzy powiązania binarne.

Modele i języki proponowane przez różnych autorów dość często nie uwzględniają faktu, że powiązania pomiędzy obiektami muszą być aktualizowane. Np. w języku OQL standardu ODMG nie można zbudować referencji do powiązania, co powoduje, że aktualizacja powiązania poprzez wyrażenie OQL staje się niemożliwa lub wymaga niestandardowych opcji. Aktualizacja powiązania oznacza operację podstawienia, która wymaga odzyskania (po lewej stronie podstawienia) referencji do powiązania, tj. identyfikatora danej przechowującej pointer.

Jeżeli pointer jest związany ze swoim bliźniaczym pointerem odwrotnym, jak na Rys.11, wówczas aktualizacja dowolnego z nich pociąga za sobą odpowiednią aktualizację dwóch bliźniaczych pointerów (znajdujących się w starym i nowym obiekcie, do których prowadził/prowadzi aktualizowany pointer). Takie rozwiązanie jest zaproponowane w standardzie ODMG (wiązanie do C++).

Zwrócimy tu jeszcze uwagę na semantykę usuwania obiektów i związanego z tym usuwania powiązań. Jeżeli w przykładzie przedstawionym na Rys.11 usuniemy obiekt Nowaka, wówczas automatycznie zostanie usunięty pointer PracujeW zawarty wewnątrz tego obiektu (i również automatycznie, bliźniaczy pointer Zatrudnia wewnątrz obiektu Firma).

Używając innej terminologii można powiedzieć, że usunięcie obiektu pociąga za sobą automatyczne kaskadowe usuwanie powiązań tego obiektu z innymi obiektami. Usunięcie obiektu, do którego prowadzi jednostronne powiązanie (np. drugiego obiektu na Rys.11), spowoduje powstanie "zwisającego pointera" (dangling pointer) (na Rys.11 pointera Prezes w obiekcie Firma). Oprócz "bliźniaczych" par pointerów istnieją inne metody unikania zwisających pointerów.

Copyrights © 2006 PJWSTK
Materiały zostały opracowane w PJWSTK w projekcie współfinansowanym ze środków EFS.