Transakcyjność w metodach logiki biznesowej i sterowanie kodem za pomocą wyjątków¶
W metodach logiki biznesowej, które są wywoływane z metod interfejsowych wszystkie operacje w bazie danych o zadanym aliasie są wykonywane w ramach jednej transakcji. Transakcja ta jest domyślnie zatwierdzana po zakończeniu metody biznesowej chyba, że w trakcie jej trwania wystąpił nieprzechwycony wyjątek. Wyjątki mogą być rzucane przez bazę danych lub bezpośrednio z kodu C#.
Rozważmy przykład metody ChangeState z obiektu TOWARY z projektu SZKOLENIE. Metoda dla wybranego jednego lub więcej towarów z listy ma zmienić ich aktywność w taki sposób, że towar aktywny ma się stać nieaktywny i na odwrót. Ponieważ operacja może być wykonywana dla potencjalnie więcej niż jednego towaru, musimy wziąć pod uwagę co ma się stać, gdy któraś z operacji będzie niemożliwa do wykonania (na przykład wskutek założenia blokady itp). Rozważmy kilka możliwych jej implementacji.
Każda operacja zmiany stanu towaru w osobnej transakcji, brak obsługi błędów¶
W metodzie interfejsowej iterujemy po wybranych towarach i dla każdego z nich wywołujemy metodę logiki biznesowej zmieniającą jego stan. Nie wyłapujemy żadnych ewentualnych wyjątków.
Metoda logiki wygląda w następujący sposób:
Przerabiając kod na metodę logiki biznesowej jedna rzecz wymaga komentarza. W oryginalnej procedurze znajdował się fragment
Fragment ten nie skompiluje się w nowym trybie. Metody bazodanowe w neosie zwracały wartość logiczną czy ich wykonanie udało się czy nie. Powodowało to dwa problemy:
-
Kod był udekorowany w drabinkę ifów przez co tracił na czytelności, często zdarzało się, że gdy wystąpił błąd jakiś else w drabince nie był zdefiniowany i nie wiadomo było co się stało
-
Gdy wystąpił błąd nie bardzo wiadomo było dokładnie jaki, w logach neosa ta informacja była dostępna, ale w kodzie programista miał dostęp tylko do zmiennej LastError, która była globalna dla bazy, nie było więc pewności, o którym błędzie informacje zawiera
Dlatego po rozdzieleniu logiki metody bazodanowe, na przykład RunSQL, w przypadku błędów zwracają wyjątek. Gdyby programista chciał zareagować na błąd, powinien ten wyjątek przechwycić. Tak napisany kod będzie działał w taki sposób, że gdy próba zmiany stanu danej krotki się nie powiedzie:
-
wszystkie wcześniej przetworzone towary zmienią stan (każda w swojej transakcji)
-
towar z błędem (blokadą) nie zmieni stanu, bo próba jego zmiany rzuci wyjątkiem, który zrollbackuje transakcję
-
operacja zmiany stanu dla pozostałych towarów się nie wykona, bo wyjątek nie został przechwycony, więc przerwie również wykonywanie metody interfejsowej
Wszystkie operacje zmiany stanu towaru w jednej transakcji, brak obsługi błędów¶
W metodzie interfejsowej iterujemy po wybranych towarach i zbieramy do listy wszystkie KTMy zaznaczonych towarów i taką listę przekazujemy do metody logiki biznesowej
Wtedy metoda logiki biznesowej powinna wyglądać w następujący sposób:
Tak napisany kod będzie działał w taki sposób, że gdy próba zmiany stanu danej krotki się nie powiedzie:
-
żaden wcześniej przetworzony towar nie zmieni stanu (wszystkie były w tej samej transakcji, która zostanie wycofana)
-
towar z błędem (blokadą) nie zmieni stanu, bo próba jego zmiany rzuci wyjątkiem, który wycofa transakcję
-
operacja zmiany stanu dla pozostałych towarów się nie wykona, bo wyjątek nie został przechwycony, więc przerwie wykonywanie metody logiki biznesowej
Wszystkie operacje zmiany stanu towaru w jednej transakcji, obsługujemy błędy¶
Metoda interfejsowa wygląda tak samo jak w poprzednim przykładzie. W metodzie logiki biznesowej dodajemy obsługę błędów:
Tak napisany kod będzie działał w następujący sposób, gdy próba zmiany stanu danej krotki się nie powiedzie:
-
wszystkie wcześniej przetworzone towary zmienią stan (wszystkie w tej samej transakcji)
-
towar z błędem (blokadą) nie zmieni stanu, bo baza danych na to nie pozwoli, wywołanie RunSQL rzuci też wyjątek, ale zostanie on przechwycony, więc nie przerwie transakcji
-
operacja zmiany stanu dla pozostałych towarów się wykona, bo wyjątek został przechwycony, więc pętla nie zostanie przerwana
-
na koniec metody logiki biznesowej transakcja zostanie zatwierdzona
Wykonywanie operacji biznesowych w osobnej transakcji¶
Czasami zachodzi konieczność wykonania pewnej operacji bazodanowej w przypadku gdy główna transakcja zostanie zrollbackowana na skutek błędu. Załóżmy, że w naszym przykładzie w przypadku błędu chcemy, żeby żaden towar nie zmienił stanu, ale dodatkowo, chcielibyśmy wysłać maila aby powiadomić kogoś o problemie. Aby osiągnąć opisany efekt użyjemy metody RunInAutonomousTransaction w następujący sposób:
Sekcja służąca do wyłapywania wyjątków wysyła maila za pośrednictwem tabeli S_MESSAGES. Mail zostanie wysłany pomimo tego, że wycofamy transakcję w której zmienialiśmy stany towarom. Wycofanie transakcji osiągamy poprzez rzucenie wyjątku Exception, gdzie pierwszym argumentem jest krótki opis. Dodatkowo można dodać bardziej szczegółowe informacje w postaci obiektu wyjątku.
Wykonywanie operacji bazodanowych w transakcji readonly¶
Metody logiki nie dają możliwości stworzenia transakcji read only, zamiast tego można wykorzystać metody GUI.QuerySQL i GUI.RunProcedure dostępne z metody interfejsowej. O sterowaniu ustawieniami transakcji w Neosie można poczytać więcej tutaj.