Przejdź do treści

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.