Modyfikacje baz danych

Grupa docelowa

Każdy deweloper wprowadzający zmiany w schemacie bazy danych powinien być zaznajomiony z podstawową zasadą działania narzędzi generujących.

Wymagania wstępne

Do zrozumienia niniejszego artykułu wymagana jest znajomość podstaw działania usługi persystencji. Szczegółowe informacje dotyczące usługi persystencji znajdują się w artykule Persistence service.

Opis

Zmiany modelu danych w obiektach biznesowych (Business Object) muszą być starannie zaplanowane, ponieważ nieprawidłowo przeprowadzone modyfikacje mogą prowadzić do utraty danych u klienta. Zmiany modelu danych powinny być wykonywane w systemie produkcyjnym możliwie jak najszybciej.

Klasa aktualizacji zawiera reguły oraz algorytmy umożliwiające realizację zadań związanych ze zmianami modelu danych. Zakres klasy aktualizacji ogranicza się do zadań podstawowych, czyli operacji wykonywanych na kolumnach obiektu biznesowego, takich jak inicjalizacje oraz modyfikacje. Dla każdej zmienionej kolumny obiektu biznesowego klasa aktualizacji zawiera informację określającą sposób obsługi danej zmiany.

Klasa aktualizacji jest tworzona podczas pierwszej zmiany lub nowego utworzenia obiektu biznesowego. Przy kolejnych zmianach dodawane są odpowiednie metody, które mogą lub muszą zostać zmodyfikowane przez programistę. Proces generowania nigdy nie usuwa metod ani zmiennych z klas aktualizacji – w razie potrzeby dodawane są wyłącznie nowe metody.

Klasa aktualizacji może być modyfikowana wyłącznie w tym systemie, w którym powstał lub został zmieniony powiązany obiekt biznesowy albo rozszerzenie. Takie podejście zapobiega powstawaniu konfliktów w tej klasie podczas instalowania aktualizacji oprogramowania, która ją zawiera, oraz sytuacji, w której powiązany obiekt biznesowy zostałby skonwertowany z użyciem zmodyfikowanej klasy zamiast klasy pochodzącej z aktualizacji oprogramowania.

Dla każdego obiektu biznesowego oraz każdego rozszerzenia istnieją oddzielne klasy aktualizacji. Każda z tych klas odpowiada za atrybuty przypisanego obiektu. Dzięki temu nie powstają konflikty wymagające ręcznej ingerencji, na przykład w sytuacji, gdy standardowy obiekt biznesowy jest rozszerzany za pomocą rozszerzenia. Klasy aktualizacji są zapisywane w przestrzeni nazw com.<prefiks_deweloperski>.upd, na przykład com.cisag.upd.app… lub com.cisag.upd.sys….

Klasy aktualizacji implementują logikę umożliwiającą transformację trwałych danych obiektu biznesowego lub rozszerzenia z dowolnej wersji źródłowej do aktualnej wersji docelowej.

Zmiany modelu danych są analizowane osobno dla każdej kolumny. W standardowym trybie przetwarzania wszystkie zmiany kolumn są rejestrowane z użyciem domyślnego zachowania, które może zostać nadpisane przez programistę. Różnice pomiędzy schematem źródłowym a schematem docelowym decydują o tym, które metody zostaną zastosowane.

Klasy aktualizacji obsługują następujące operacje:

  • Inicjalizacja nowych kolumn (metoda Init)
  • Stałe wartości początkowe
  • Zmiana typu danych istniejących kolumn (metoda ChangeDatatype)
  • Niezgodna zmiana typu danych

Przykład klas aktualizacji

Ten przykład ma na celu wyjaśnienie działania klas aktualizacji. Zmiany w obiekcie biznesowym i zastosowane metody klasy aktualizacji zapisano pogrubioną czcionką.

Przykład standardowy

Przykład klas aktualizacji dla zmian w standardzie

W powyższym przykładzie Business Object Item jest zmieniany dwukrotnie. Najpierw atrybut description zostaje skrócony ze 100 do 80 znaków, a następnie dodany zostaje atrybut unit.

  • Metoda changeDatatype€description€str100_str80 – oblicza niekompatybilną zmianę typu danych atrybutu description ze 100 do 80 znaków

  • Metoda init€unit – oblicza wartość początkową dla nowego atrybutu unit

Metody są wywoływane podczas wykonywania zmiany modelu danych.

Przykład rozwoju partnera

Tworzenie rozszerzenia i importowanie standardowego rozszerzenia

Najpierw tworzy się rozszerzenie dla obiektu biznesowego Item z atrybutami abc_type i abc_color, a następnie importuje się wersję 1.1 obiektu Item. W przypadku rozszerzenia nie jest wymagana ręczna obsługa konfliktów w klasach aktualizacji obiektu biznesowego.

  • Metoda init€abc_type – oblicza wartość początkową dla kolumny abc_type

  • Metoda init€abc_color – oblicza wartość początkową dla kolumny abc_color

Podczas tworzenia rozszerzenia wywoływane są metody klas aktualizacji rozszerzenia. W przypadku zmiany bazowego obiektu biznesowego Item nie ma konieczności zmiany klas aktualizacji i nie są wywoływane żadne metody klasy aktualizacji rozszerzenia.

Przykład rozwoju klienta

Rozszerzenie z częścią w dostosowywaniu klienta

Analogicznie do systemu rozszerzeń partnerskich, również w systemie adaptacji klienta nie jest wymagana ręczna obsługa konfliktów w klasach aktualizacji obiektu biznesowego ani rozszerzeń obiektu biznesowego z systemu rozszerzeń partnerskich. Wraz z rozszerzeniem obiektu biznesowego XYZ_Item dodawane są atrybuty typu Part xyz_coordinate z Part Coordinate oraz xyz_length z Part Quantity.

  • Metoda init€xyz_length – oblicza wartość początkową kolumn atrybutu typu Part xyz_length.
    Part com.cisag.app.general.obj.Quantity jest traktowany przez klasy aktualizacji jako całość, dlatego może zostać zainicjalizowany jako całość i istnieje tylko jedna metoda inicjalizacji (patrz sekcja Datentypen).

  • Metody init€xyz_coordinate…€… – obliczają wartości początkowe kolumn atrybutu typu Part xyz_coordinate.
    Dla Part Coordinate nie ma specjalnego traktowania, dlatego wszystkie kolumny muszą zostać zainicjalizowane osobno i posiadają oddzielne metody inicjalizacji (patrz sekcja Datentypen).

Zmiana modelu danych

Przebieg zmiany modelu danych zależy od sposobu przeniesienia danych z wersji źródłowej do wersji docelowej.

Generowanie obiektu biznesowego podczas prac deweloperskich przebiega w następujących krokach:

Kolejność zmiany modelu danych w systemie deweloperskim

Po edycji obiektu biznesowego, widoku lub Part w aplikacji Obiekty deweloperskie należy wygenerować ten obiekt za pomocą narzędzia crtbo. Podczas tego procesu generowane są źródła Java dla klas Mapper i klas aktualizacji, a także tabele tymczasowe. Następnie, w razie potrzeby, klasy aktualizacji muszą zostać dostosowane przez dewelopera. Zmodyfikowane klasy aktualizacji umożliwiają testową konwersję danych do tabel tymczasowych.

Serwer aplikacji dewelopera uzyskuje dostęp do tabel tymczasowych (patrz następna sekcja), co umożliwia sprawdzenie, czy konwersja przebiegła pomyślnie. Po zatwierdzeniu zadania deweloperskiego dane są ponownie konwertowane, a zmiana zostaje aktywowana na wszystkich bazach danych. Po aktywowaniu zmiany modelu danych możliwe jest aktywowanie zadania deweloperskiego.

Zmiany modelu danych zazwyczaj stanowią całość wraz ze zmianami w przetwarzającym kodzie źródłowym. Możliwe jest przetestowanie konsekwencji zmiany schematu przed jej aktywowaniem, dzięki czemu unika się potencjalnego zakłócenia pracy innych użytkowników systemu. Nowe klasy Mapper utworzone w bieżącym zadaniu deweloperskim uzyskują dostęp do tabeli tymczasowej z nowym schematem i skonwertowanymi danymi, podczas gdy stare (aktywne w systemie klasy Mapper) nadal korzystają z dotychczas aktywnych tabel w starym schemacie.

Przykład stanu podczas opracowywania zmiany modelu danych

Należy pamiętać, że tabele tymczasowe są tworzone wyłącznie dla tych obiektów biznesowych, które zostały zablokowane w zadaniu deweloperskim i w nim wygenerowane. Dostęp do tych tabel jest domyślnie możliwy tylko w trybie odczytu. Z tego powodu testowanie aplikacji jest możliwe jedynie w ograniczonym zakresie. Parametr startowy serwera aplikacji -writeConvertedTables umożliwia włączenie zapisu do tabel tymczasowych. Jego użycie należy dokładnie przeanalizować, ponieważ możliwe skutki uboczne są trudne do przewidzenia.

Przykład

Jeśli w zadaniu deweloperskim zablokowano Entity, a jego zależności Dependents nie zostały zablokowane, podczas tworzenia nowej instancji Entity zostanie ona zapisana w tabeli tymczasowej, natomiast Dependents tej instancji zostaną zapisane w aktywnych tabelach.

Pozostali użytkownicy, korzystający ze starych, nadal aktywnych klas Mapper, zapisują nowe Entities wyłącznie w aktywnych tabelach. W rezultacie w bazie danych powstają niespójne stany. Podobne problemy mogą występować również w przypadku schematów numeracji i liczników.

Aby odczytać dane z tabeli tymczasowej w aplikacji OQL-Anweisungen, należy umieścić słowo kluczowe CONVERTED_TABLE pomiędzy nazwą obiektu biznesowego a nazwą aliasu. Dostęp do aktywnej tabeli odbywa się przy użyciu słowa kluczowego ACTIVE_TABLE.

Nowe tabele mogą zostać aktywowane tylko wtedy, gdy zadanie deweloperskie zostało zatwierdzone, ale nie zostało jeszcze aktywowane. Zmiany w bazie danych stają się widoczne dla innych użytkowników systemu dopiero po aktywacji. Po aktywacji obiektu biznesowego lub widoku należy ponownie uruchomić wszystkie serwery, które uzyskują dostęp do tego obiektu biznesowego.

Ogólny dostęp do obiektów biznesowych

W klasach aktualizacji nie jest możliwy dostęp do obiektów biznesowych przy użyciu standardowych klas Mapper obiektu biznesowego. Wszystkie obiekty biznesowe są odczytywane przy użyciu generycznych klas Mapper. W tej sekcji opisano generyczny dostęp do obiektów biznesowych.

Schemat obiektu

Każdy obiekt biznesowy jest w pełni opisany za pomocą metadanych. Metadane schematu obiektu biznesowego można odczytać jako com.cisag.pgm.appserver.CisObjectSchema w CisObjectManager.

W klasach aktualizacji schemat źródłowy i docelowy zmiany modelu danych można odczytać za pomocą metod CisUpdateBase:getFromSchema oraz CisUpdateBase:getToSchema.

Schemat zawiera między innymi opis wszystkich kolumn obiektu biznesowego. Opis kolumn można odczytać w schemacie za pomocą metod CisObjectSchema:getColumn oraz CisObjectSchema:getColumns.

Uwaga
Na podstawie schematu i odczytu opisu kolumn możliwe jest sprawdzenie, czy w schemacie źródłowym podczas zmiany modelu danych istnieje już określona kolumna.

Dostęp ogólny

Usługa persystencji standardowo uzyskuje dostęp do obiektów biznesowych za pomocą wygenerowanych klas Business Object Mapper. Klasy Mapper muszą dokładnie odpowiadać tabeli wygenerowanej w bazie danych, w przeciwnym razie dane nie mogą być poprawnie odczytywane i zapisywane. Dla historycznych wersji obiektu biznesowego takie klasy Mapper nie są już dostępne.

Klasa com.cisag.pgm.datatype.CisGenericObject umożliwia generyczny dostęp do dowolnych wersji obiektu biznesowego. Klasy aktualizacji wykorzystują te generyczne obiekty podczas zmian modelu danych. Każdy dostęp do usługi persystencji, np. getObject, który w normalnym przypadku zwraca instancję obiektu biznesowego, w klasach aktualizacji zwraca obiekt generyczny.

Podczas generycznego dostępu do obiektów biznesowych można używać wszystkich metod dostępu Object Managera, np. getObject, getObjectIterator, getResultSet itd. Object Manager zawsze uzyskuje dostęp do wersji obiektu biznesowego aktualnie aktywnej w bazie danych. Dzięki generycznemu dostępowi możliwe jest odczytanie stanu bazy danych sprzed zmiany modelu danych. Nie jest natomiast możliwy dostęp do wyniku transformacji danych. Nie można również używać metod Object Managera służących do zapisu w bazie danych – możliwy jest wyłącznie odczyt danych.

Kolumny generycznego obiektu biznesowego mogą być odczytywane za pomocą ścieżki atrybutu. Dla każdego prymitywnego typu danych oraz dla Special Parts dostępne są odpowiednie metody Get i Set.

Aby sprawdzić, czy dla kolumny atrybutu typu Part można odczytać prawidłową wartość, zapytanie kolumny logicznej tego atrybutu Part musi zwrócić wartość prawda. Nazwa tej kolumny odpowiada ścieżce atrybutu Part.

Za pomocą metody buildPrimaryKey można utworzyć klucz główny lub zależny od czasu klucz główny obiektu biznesowego.

Przykład
Przykład użycia CisGenericObject z CisObjectManager:

CisGenericObject item = (CisGenericObject)om.getObject(
CisGenericObject.buildPrimaryKey(
“com.cisag.app.general.obj.Item“,itemGuid)
oldDescription=item.getString(”description“);

Należy zwrócić uwagę, że odczyt atrybutu daty lub znacznika czasu, którego logiczny typ danych bazuje na typie logicznym com.cisag.sys.kernel.ObjectTimeStamp, musi być wykonywany metodą getTimeStamp(), która zwraca obiekt java.util.Date. W razie potrzeby wartość CisDate należy utworzyć samodzielnie.

Przykład

Date dateValue = item.getTimeStamp(“purchaseStatusDate”);
Byte[] timeZoneGuid = item.getGuid(“_timeZoneGuid”);
CisDate purchaseStatusDate =
com.cisag.pgm.datatype.CisDateUtility.createCisDate(timeZoneGuid,
dateValue);

Korzystanie z transakcji

Przed wywołaniem metody klasy aktualizacji system automatycznie otwiera transakcję dla bazy danych, która ma zostać poddana konwersji. Dzięki temu wszystkie standardowe użycia Object Managera działają w odpowiednim kontekście transakcji. W przypadku korzystania z automatycznie otwartej transakcji nie jest możliwe użycie podtransakcji.

Dozwolone jest otwarcie dodatkowej transakcji najwyższego poziomu za pomocą metody menedżera transakcji beginNew(byte[] databaseGuid). Przekazana GUID bazy danych musi odpowiadać GUID bazy danych, która ma zostać poddana konwersji. Wartość tę należy ustalić za pomocą metody getDatabaseGuid() klasy aktualizacji.

Dla nowo utworzonej transakcji możliwe jest również tworzenie podtransakcji.

Klasy aktualizacji

Klasy aktualizacji określają, w jaki sposób dane zapisane w schemacie źródłowym są przenoszone do schematu docelowego. Klasy aktualizacji definiują transformację danych dla każdej kolumny w obiekcie biznesowym za pomocą metod Init oraz ChangeDatatype.

W sekcji Opis przedstawiono klasę aktualizacji dla obiektów biznesowych i rozszerzeń. W tej sekcji opisano sposób implementacji zmiany modelu danych przez dewelopera w tej klasie aktualizacji.

Metoda Init

Metoda Init oblicza wartość początkową podczas tworzenia nowej kolumny. Wartość początkowa jest wymagana wtedy, gdy kolumna istnieje w schemacie docelowym, ale nie występuje w schemacie źródłowym. Metoda Init jest generowana w klasie aktualizacji z ustaloną wartością początkową. W razie potrzeby metoda Init może zostać zmieniona w klasie aktualizacji w celu obliczenia innej wartości początkowej.

Nazwa metody Init jest tworzona według następującego schematu:

<Java-Datatype> init€<AttributePath> ()

Ścieżka atrybutu kolumny odpowiada nazwie kolumny w OQL. Nawiasy kwadratowe [] oraz kropka . są jednak zastępowane znakiem dolara $, aby ścieżka atrybutu mogła zostać użyta jako identyfikator metody.

Przykład
Jeśli ścieżka atrybutu w OQL ma postać discounts[1].discountType, w nazwie metody zostanie użyty ciąg znaków discounts$1$$discountType.

Sekcja Datentypen zawiera dodatkowe informacje dotyczące typu danych w nazwie metody.

Dla atrybutu typu Part oprócz metod Init powiązanych kolumn generowana jest dodatkowo metoda Init dla logicznej kolumny Part. Jako ścieżkę atrybutu wykorzystuje ona ścieżkę atrybutu Part. Wartość zwracana przez metodę określa, czy wartość Part jest prawidłowa. Aby zainicjalizować atrybut Part wartością, metoda Init logicznej kolumny Part musi zostać nadpisana tak, aby zwracała wartość true.

Metoda Init jest generowana w klasie aktualizacji obiektu biznesowego, jeśli kolumna należy do atrybutu obiektu biznesowego. Jeśli kolumna należy do atrybutu rozszerzenia obiektu biznesowego, metoda Init jest generowana w klasie aktualizacji rozszerzenia obiektu biznesowego.

Przykład

Obliczenie wartości początkowej kolumny description z typem danych String i długością 100.

  • Klasa aktualizacji – wygenerowana

String init€description () {
return “”;
}

  • Klasa aktualizacji – zmodyfikowana przez dewelopera
String init€description() {
return “Artikel”);
}