History


Opis modułu

Moduł służy do rejestracji informacji o zmianach w tych tabelach bazy danych, które posiadają numeryczny klucz główny w polu o nazwie id. Zmiany dotyczące różnych tabel zapisywane są w jednej tabeli historii, domyślnie p_history. Tabela p_history jest tabelą domyślnie tworzoną przez jPALIO.

Jeżeli zachodzi potrzeba wydzielenia części historii do innej tabeli (np. historii zmian stanów, ze względu np. na dużą ilość wyszukiwań po tej części danych), to należy utworzyć osobną tabelę historii (np. states_history) i odpowiadającą jej sekwencję (states_history_s) zgodnie z formatem podanym w rozdziale Konfiguracja, a następnie do rejestracji zmian używać funkcji modułu history posiadających argument historyTableName, przy czym w tym argumencie należy podać nazwę dodatkowo utworzonej tabeli historii (states_history). Opisany sposób umożliwia utworzenie dowolnej liczby tabel z historią.

Moduł jest dostępny jako standardowy w każdej instancji jPalio.

Konfiguracja

Tabele historii używane przez moduł muszą mieć postać:

Wymagane jest także utworzenie sekwencji o nazwie takiej jak nazwa tabeli z dołączonym suffiksem "_s", np. dla tabeli "extra_history" powinna zostać utworzona sekwencja "extra_history_s".

Przykładowy skrypt tworzący tabelę "extra_history" i odpowiadającą jej sekwencję dla Oracle:

create table extra_history (
  id number(38) not null constraints his_pk primary key,
  resource_name varchar2(40) not null,
  field_name varchar2(40) not null,
  row_id number(38) not null,
  old_value varchar2(4000),
  new_value varchar2(4000),
  token number(2),
  extra_id number(38),
  creation_timestamp date not null,
  creation_user_id number(6) not null
);
create sequence extra_history_s start with 1;

Znaczenie pól w tabeli historii:

Przykłady

Typowe użycie modułu historii:

$// zmiana imienia klienta o id=35 z "Jan" na "Kazimierz"
$=(@customerId, 35)
$=(@oldFirstName, "Jan")
$=(@newFirstName, "Kazimierz")
$sql.write("update customers set first_name=? where id=?", [$@newFirstName, $@customerId])
$=(@historyId, $history.recordChange("customers", "first_name", $@customerId, $@oldFirstName, $@newFirstName))

Wywołanie z powyższego przykładu odpowiada następującemu pełnemu wywołaniu funkcji recordChange:

$=(@historyId, $history.recordChange("data", "p_history", "customers", "first_name", $@customerId, $@oldFirstName, $@newFirstName, $user.userID(), (Long)null, (String)null))

Jeżeli poprzednia wartość imienia nie jest znana, to aby osiągnąć taki sam efekt jak powyżej można użyć następującej konstrukcji (funkcja sama odczyta poprzednią wartość):

$=(@customerId, 35)
$=(@newFirstName, "Kazimierz")
$history.modifyH("customers", "first_name", $@customerId, $@newFirstName)

Jeżeli zmiany są wykonywane w zadaniu, to id użytkownika nie jest znane (sesja użytkonika nie jest utworzona). Można wtedy przypisać zmiany do użytkownika specjalnego używając funkcji modułu w wersji z argumentem userId:

$=(@customerId, 35)
$=(@oldFirstName, "Jan")
$=(@newFirstName, "Kazimierz")
$=(@specialUserId, -1) $// id użytkownika specjalnego
$sql.write("update customers set first_name=? where id=?", [$@newFirstName, $@customerId])
$=(@historyId, $history.recordChange("customers", "first_name", $@customerId, $@oldFirstName, $@newFirstName, $@specialUserId))

Niekiedy istotne jest, aby zarejestrować w historii nie tylko zmianę wartości pola, ale także fakt próby modyfikacji pola, nawet jeśli wartość faktycznie nie uległa zmianie. Należy wtedy zastosować wywołania funkcji z argumentem saveAlways:

$=(@customerId, 35)
$=(@oldFirstName, "Jan")
$=(@newFirstName, "Jan")
$sql.write("update customers set first_name=? where id=?", [$@newFirstName, $@customerId])
$// wpis w historii zostanie dokonany mimo iż $@oldFirstName == $@newFirstName
$=(@historyId, $history.recordChange("customers", "first_name", $@customerId, $@oldFirstName, $@newFirstName, $user.userID(), (Long)null, "Y"))

Do rejestracji zmian w polach numerycznych służy ta sama funkcja, która zapisuje zmiany w polach tekstowych:

$=(@customerId, 35)
$=(@oldStreetNr, 2)
$=(@newStreetNr, 7)
$sql.write("update customers set street_nr=? where id=?", [$@newStreetNr, $@customerId])
$=(@historyId, $history.recordChange("customers", "street_nr", $@customerId, $toString($@oldStreetNr), $toString($@newStreetNr)))

Do zmian w polach daty można stosować przeznaczoną do tego celu funkcję recordDateChange (i modifyDateH):

$=(@dateFormat, "yyyy.MM.dd")
$=(@customerId, 35)
$=(@newLastContactDate, $sysDate())
$// rejestracja zmiany w historii musi być przed wykonaniem zmiany, ponieważ recordDateChange odczyta poprzednią wartość pola last_contact_date bezpośrednio z bazy
$=(@historyId, $history.recordDateChange("customers", "last_contact_date", $@customerId, $toString($@newLastContactDate, $@dateFormat), $@dateFormat))
$sql.write("update customers set last_contact_date=? where id=?", [$@newLastContactDate, $@customerId])

Zmiany w polach daty można rejestrować także zwykłą funkcją recordChange:

$=(@dateFormat, "yyyy.MM.dd")
$=(@customerId, 35)
$=(@oldLastContactDate, "2011.01.01")
$=(@newLastContactDate, $sysDate())
$sql.write("update customers set last_contact_date=? where id=?", [$@newLastContactDate, $@customerId])
$=(@historyId, $history.recordChange("customers", "last_contact_date", $@customerId, $@oldLastContactDate, $toString($@newLastContactDate, $@dateFormat)))

Historia dla tabel złączeniowych

Moduł umożliwia rejestrację informacji o zmianach danych w tabelach złączeniowych. Do tego celu jest używane pole extra_id w tabeli historii oraz funkcje modułu w wersji posiadającej parametr extraId. Typowo zmiana w tabeli złączeniowej przypisywana jest do jednej z tabel wchodzących w skład złączenia, np. mając tabele A i B oraz tabelę złączeniową A_B, zmianę w tabeli A_B rejestruje się jako przypisaną do tabeli A (lub B), z nazwą tabeli A (lub B) i kolumny nie istniejącej w tabeli A (lub B) tylko w tabeli A_B. Wtedy row_id to klucz główny tabeli A (lub B) a extra_id to klucz główny z drugiej tabeli wchodzącej w skład złączenia: B (lub A).

Rejestracja danych dla tabel złączeniowych najczęściej występuje w dwóch przedstawionych poniżej sytuacjach. Pierwszy przypadek to typowa tabela złączeniowa:

Załóżmy, że istnieje rola o id=7 i przywilej o id=4. Zmiana polegająca na przypisaniu przywileju 4 do roli 7 mogłaby zostać zarejestrowana w historii jako:

$=(@historyId, $history.recordChange("p_roles", "p_priv_id", 7, (String)null, "4", $user.userID(), 4))

lub

$=(@historyId, $history.recordChange("p_privs", "p_role_id", 4, (String)null, "7", $user.userID(), 7))

Wybór wersji należy do projektanta aplikacji, jednakże w tym przypadku pierwsza propozycja wydaje się bardziej logiczna, ponieważ to przywileje są grupowane za pomocą ról a nie na odwrót.

Druga sytuacja, w której możliwe jest wykorzystanie pola extra_id w tabelach historii przedstawiona jest poniżej:

Istnieje tu tabela documents_params, która nie jest typową tabelą złączeniową - posiada własny klucz główny a nie klucz złożony z kluczy głównych tabel nadrzędnych. Logicznie pełni ona jednak rolę tabeli złączeniowej, ale takiej, w której wpisy dotyczące złączenia mogą się powtarzać - w jednym dokumencie można mieć wiele parametrów danego typu z różnymi wartościami. Tabela ta mogłaby więc posiadać własne wpisy w historii, niezależne od tabel nadrzędnych. Można jednak oczekiwać, iż wartości parametrów, jako integralna część dokumentów, będą miały swoją historię związaną z tabelą documents a nie documents_params.

Załóżmy, że w tabeli params_dictionary mamy wpis o id=2, w documents wpis o id=4, a w documents_params wpis o (id=16, document_id=4, params_dictionary_id=2, param_value="ala"). Rejestracja historii dla tego parametru dokumentu w wersji skojarzonej w tabelą documents a nie documents_params może wyglądać następująco:

$=(@historyId, $history.recordChange("documents", "param_value", 4, (String)null, "ala", $user.userID(), 16))

Jeżeli z tabelą podstawową związana jest więcej niż jedna tabela złączeniowa, to sposób rejestracji zmian w tych tabelach powinien zostać ustalony przez osobę piszącą aplikację - można np. w polu column_name zapisywać wartość nazwa_tabeli_złączeniowej#nazwa_kolumny_w_tabeli_złączeniowej zamiast tylko nazwa_kolumny_w_tabeli_złączeniowej.

Funkcje modułu history

Moduł posiada niewielką liczbę funkcji, są one jednak mocno przeciążone. Poniższa tabela pozwoli łatwo zorientować się w zestawie dostępnych funkcji.

zwracany argument metoda zapis do historii modyfikacja pola nazwa i typ argumentu
connectorName historyTableName resourceName fieldName rowId oldValue newValue
(pozostałe zmiany)
newValue
(zmiany pól z datą)
dateFormat userId extraId saveAlways
String String String String Long String String String String Long Long String
Long recordChange X X X X X
X X X X X X
X X X X X X
X X X X X X X
X X X X X X X X
X X X X X X X X X
X X X X X X
X X X X X X X
X X X X X X X
X X X X X X X X
X X X X X X X X X
X X X X X X X X X X
X X X X X X X X X X X
Long recordDateChange X X X X X X
X X X X X X X
X X X X X X X
X X X X X X X X
void modify X X X X X
void modifyAndTrim X X X X X
void modifyDate X X X X X X
void modifyH X X X X X X
X X X X X X X
X X X X X X X
X X X X X X X X
void modifyAndTrimH X X X X X X
X X X X X X X
X X X X X X X
X X X X X X X X
void modifyDateH X X X X X X X
X X X X X X X X
X X X X X X X X
X X X X X X X X X

Większość argumentów przekazywanych do funkcji modułu jest wspólna. Znaczenie tych argumentów jest opisane poniżej.

Wartości domyślne argumentów są następujące:

Funkcje recordChange oraz recordDateChange zwracają wartość Long, która jest identyfikatorem wpisu dokonanego w tabeli historii.