ZSBD-2st-1.2-lab6.tresc-1.3-Slajd9
Odczytywanie złożonych struktur
Odczytanie obiektu z bazy danych może wymagać odczytania również wszystkich obiektów osiągalnych poprzez referencje z odczytywanego obiektu. Odczytanie tychże obiektów może prowadzić do odczytania kolejnych obiektów. W skrajnym przypadku, odczytanie jednego obiektu może prowadzić do wczytania do pamięci komputera całej bazy danych. Przykładowo, obiekt A na przykładzie (1) jest powiązany bezpośrednio, lub pośrednio z każdym obiektem w bazie danych. W związku z tym, jeżeli obiekt A zostałby odczytany, to wszystkie inne obiekty w bazie danych musiałyby również zostać odczytane. Taki efekt jest najczęściej niepożądany i dlatego db4o wprowadza kilka mechanizmów pozwalających na ograniczenie tego problemu. Podstawowym rozwiązaniem problemu jest ustalenie liczby kolejnych powiązań referencyjnych wzdłuż których db4o będzie nawigować w celu odczytywania obiektów powiązanych z obiektem odczytanym w wyniku realizacji zapytania, przy czym pierwszym powiązaniem referencyjnym jest powiązanie do odczytywanego obiektu. Jest to tzw. głębokość aktywacji. Przykładowo, dla głębokości aktywacji równej dwa, przy odczytywaniu obiektu A (przykład (2)) odczytane zostaną również obiekty osiągalne z obiektu A wzdłuż jednego powiązania referencyjnego (pierwsze powiązanie do obiektu A i drugie powiązanie do kolejnych). Na przykładzie (2) są to obiekty B, C i D. Obiekty, które zostały odczytane z bazy danych i znajdują się pamięci, nazywa się obiektami aktywnymi. Obiekty aktywne zaznaczono na rysunku kolorem pomarańczowym. Pozostałe obiekty, które nie zostały odczytane z bazy danych (zaznaczone na czarno) nazywa się obiektami nieaktywnymi. Niech zmienna refA zawiera referencję na obiekt A odczytany przy poziomie aktywacji 2. Niech obiekt A zawiera pola, które stanowią referencje na obiekty B, C i D o nazwach refB, refC i refD odpowiednio. Niech obiekt B posiada pole stanowiące referencję na obiekt E o nazwie refE, a obiekt C posiada pole stanowiące referencję na obiekt F o nazwie refF. Przy tych założeniach, następujące wyrażenia ścieżkowe są poprawne:
refA.refB.refE
refA.refC.refF
refA.refD
Nawigowanie poza obiekty E i F nie jest możliwe, gdyż obiekty te nie są aktywne. Jeżeli obiekt jest nieaktywny, to wszystkie jego pola zawierają wartości domyślne (null, 0, false). W przypadku referencji jest to wartość null. Próba nawigacji poprzez referencję o wartości null zakończyłaby się wyjątkiem NullPointerException.
Jeżeli zajdzie konieczność odczytania nieaktywnego obiektu, na którego jest znana referencja (np. refF), Możliwa jest aktywacja takiego obiektu za pomocą metody activate interfejsu ObjectContainer. Metoda ta przyjmuje dwa parametry: referencję na obiekt i głębokość aktywacji. W wyniku wywołania tej metody aktywowane są wszystkie obiekty, począwszy od obiektu przekazanego jako parametr, wzdłuż pewnej liczby kolejnych powiązań referencyjnych równych głębokości aktywacji.
Przykładowo, aktywacja obiektu wskazywanego przez referencję refF i wszystkich obiektów osiągalnych poprzez ten obiekt (głębokość aktywacji równa 1) wyglądałaby następująco:
db.activate(refA.refC.refF,1);
Istnieje również metoda o działaniu odwrotnym do metody activate, o nazwie deactivate, która powoduje deaktywację i zwolnienie pamięci zajmowanej przez obiekty. Ponieważ jednak metoda ta nie wchodzi w zakres ćwiczeń, pominiemy ją.
Istnieje również metoda pozwalająca na sprawdzenie, czy obiekt wskazywany przez referencję jest aktywny. Jest to metoda isActive interfejsu ExtObjectContainer. Metoda isActive jako parametr przyjmuje jedynie referencję na sprawdzany obiekt. Przykładowo, sprawdzenie, czy obiekt wskazywany przez referencję refF jest aktywny wyglądałoby następująco:
if (db.ext().isActive(refA.refC.refF)) {
//aktywny
} else {
//nieaktywny
}
(Uwaga! W przyszłych wersjach db4o, metoda isActive może zostać przeniesiona do interfejsu ObjectContainer. Wówczas aktywacja tej metody będzie wyglądać następująco:
db.isActive(refA.refC.refF)
).
Głębokość aktywacji może być ustalony zarówno globalnie dla wszystkich klas, jak i dla każdej z klas z osobna oraz dla każdego pola każdej klasy z osobna. Domyślna globalna głębokość aktywacji wynosi 5, ale można ją zmienić za pomocą metody activationDepth zdefiniowanej w interfejsie Configuration. W celu uzyskania referencji na obiekt implementujący ten interfejs należy wykorzystać statyczną metodę klasy Db4o o nazwie configure. Przykładowo, ustalenie poziomu aktywacji na 10 wygląda następująco:
Db4o.configure().activationDepth(10);
Operacja ta musi zostać wykonana przed otwarciem połączenia, czyli przed utworzeniem obiektu implementującego interfejs ObjectContainer (np. metodą openFile klasy Db4o). Konfiguracja poziomu aktywacji dla poszczególnych klas z osobna jest poza zakresem ćwiczeń. Osoby zainteresowane powinny zajrzeć do dokumentacji, bądź tutoriala db4o.
Prócz wyżej opisanych metod istnieje również metoda pozwalająca na takie skonfigurowanie db4o, że odczytanie obiektów konkretnych klas powoduje automatyczne odczytanie obiektów z nich osiągalnych z pominięciem ograniczenia na głębokość aktywacji. Nie wchodzi to jednak w zakres ćwiczeń.