Access
 sql >> Baza danych >  >> RDS >> Access

Obsługa błędów na poziomie absolwenta

Lubię dobrą układankę tak samo jak następny facet. Jest coś satysfakcjonującego w zaczynaniu od stosu pozornie przypadkowych elementów i obserwowaniu, jak obraz powoli odbiera życie, gdy przywracasz porządek w chaosie.

Przestałem jednak układać puzzle. Minęło chyba 13 lat. Pozwól mi policzyć. Mam czworo dzieci; najstarsza ma 15 lat. Tak, dwa lata ma rację, kiedy była na tyle dorosła, że ​​mogła podejść do niedokończonej układanki, uciec z jednym z kawałków i nakarmić nim psa, termometr lub toaletę.

I tak satysfakcjonujące, jak umieszczenie ostatniego elementu w układance, tak samo miażdżące duszę jest umieszczenie przedostatniego elementu w układance i uświadomienie sobie, że brakuje ostatniego elementu.

Tak właśnie myślałem o moim kodzie obsługi błędów.

Inspektor zmiennych vbWatchdog

Jeśli używasz vbWatchdog do obsługi błędów (powinieneś), powinieneś znać jedną z jego najpotężniejszych funkcji:Inspektor zmiennych. Ten obiekt zapewnia dostęp do każdej zmiennej w zakresie na każdym poziomie stosu wywołań. Ten poziom szczegółowości jest cyfrowym złotem, gdy przychodzi czas na rozwiązywanie problemów.

Przez lata rozwijałem zaawansowany moduł obsługi błędów, który rejestruje wszystkie te informacje. Kiedy dopracowałem sposób obsługi błędów, jedna skaza zaczęła się wyróżniać. Chociaż mogłem wyodrębnić wartości większości moich zmiennych, wszystko, co mogłem uzyskać ze zmiennych obiektowych, to „Nic” lub „{Object}”.

To nie jest pukanie do vbWatchdog. Przedmiotem może być wszystko. Jaką inną wartość może pokazać? Mimo to ten brakujący element układanki mnie gryzł. Czułem, jak wszechświat się ze mnie śmieje, kiedy rozwiązywałem jakiś błąd, a klucz do rozwiązania tego problemu krył się za tym jednym irytująco nieprzyjemnym słowem „{Object}”.

Gdybym tylko miał jakiś sposób na poznanie jednej lub dwóch właściwości identyfikujących ten obiekt, mógłbym dokładnie określić, co się dzieje.

Pierwsza próba

Moją pierwszą próbą rozwiązania problemu jest narzędzie każdego sfrustrowanego programisty:brutalna siła. W moim globalnym module obsługi błędów dodałem Wybierz... przypadek instrukcja wokół .TypeDesc .

Na przykład mam klasę konstruktora SQL, którą nazywam clsSQL . Jedną z właściwości tej klasy jest .LastSQL . Ta właściwość zawiera ostatnią instrukcję SQL zbudowaną lub wykonaną przez klasę. Może to być instrukcja SELECT lub INSERT/UPDATE/DELETE/itd. (Zapożyczyłem pomysł z obiektu DAL web2py. )

Oto część mojego globalnego programu obsługi błędów:

Select Case .TypeDesc
Case "clsSQL"
    If Not .Value Is Nothing Then
        ThisVar = .Name & ".LastSQL = " & .Value.LastSQL
    End If

Z biegiem czasu zacząłem dodawać do tej listy dodatkowe typy obiektów niestandardowych. W przypadku każdego typu niestandardowego musiałbym pobrać inną niestandardową właściwość.

Miałem swój ostatni element układanki. Problem polega na tym, że znalazłem go unoszącego się w misce z wodą psa, pogryzionego z jednej strony. Myślę, że można powiedzieć, że moja łamigłówka była kompletna, ale to było pyrrusowe zwycięstwo.

Lekarstwo, które wyrządza więcej szkody niż pożytku

Szybko zdałem sobie sprawę, że to rozwiązanie nie będzie się skalować. Było wiele problemów. Po pierwsze, mój globalny kod obsługi błędów będzie rozdęty. Trzymam mój kod obsługi błędów w jednym standardowym module w mojej bibliotece kodu. Oznacza to, że za każdym razem, gdy chciałem dodać obsługę modułu klasy, ten kod byłby dodawany do każdego z moich projektów. Było to prawdą, nawet jeśli moduł klasy był używany tylko w jednym projekcie.

Kolejnym problemem jest to, że wprowadzałem zewnętrzne zależności do mojego kodu obsługi błędów. Co się stanie, jeśli zmienię mój clsSQL? kiedyś klasę i zmień nazwę lub usuń .LastSQL metoda? Jakie są szanse, że zdałem sobie sprawę, że taka zależność istniała podczas pracy w moim clsSQL klasa? Takie podejście szybko by się załamało pod własnym ciężarem, chyba że wymyślę alternatywę.

Szukam rozwiązania w Pythonie

Zdałem sobie sprawę, że to, czego naprawdę chciałem, to jakiś sposób na określenie kanonicznej reprezentacji obiektu z wnętrza tego obiektu . Chciałem móc zrealizować tę reprezentację tak prosto lub kompleksowo, jak to konieczne. Chciałem mieć gwarancję, że nie wybuchnie w czasie działania. Chciałem, żeby było to całkowicie opcjonalne dla każdego modułu zajęć.

Wygląda na to, że lista życzeń jest długa, ale udało mi się zaspokoić każdą pozycję na niej dzięki rozwiązaniu, które znalazłem.

Po raz kolejny zapożyczyłem pomysł z Pythona. Wszystkie obiekty Pythona mają specjalną właściwość znaną jako ._repr . Ta właściwość jest ciągiem reprezentującym obiekt. Domyślnie zwróci nazwę typu i adres pamięci instancji obiektu. Jednak programiści Pythona mogą zdefiniować .__repr__ metoda zastępująca zachowanie domyślne. To jest ten soczysty kawałek, którego chciałem na zajęciach VBA.

W końcu znalazłem idealne rozwiązanie. Niestety znalazłem go w innym języku, w którym rozwiązanie jest w rzeczywistości cechą samego języka . Jak to ma mi pomóc w VBA? Okazuje się, że pomysł był ważną częścią; Musiałem po prostu wykazać się kreatywnością podczas implementacji.

Interfejsy na ratunek

Aby przemycić tę koncepcję Pythona do VBA, zwróciłem się do rzadko używanej funkcji języka:interfejsów i operatora TypeOf. Oto jak to działa.

Utworzyłem moduł zajęć, który nazwałem iRepresentation . Interfejsy w większości języków są nazywane zgodnie z konwencją z wiodącym „i”. Oczywiście możesz nazwać swoje moduły, jak chcesz. Oto pełny kod mojej iRepresentation klasa.

iRepresentation.cls

`--== iRepresentation ==-- class module
Option Compare Database
Option Explicit

Public Property Get Repr() As String
End Property

Powinienem zaznaczyć, że nie ma nic szczególnego w module klasy, który służy jako interfejs w VBA. Rozumiem przez to, że nie ma słowa kluczowego na poziomie modułu ani ukrytego atrybutu, który musimy ustawić. Możemy nawet utworzyć instancję nowego obiektu za pomocą tego typu, choć nie byłoby to zbyt ważne (jeden wyjątek to testowanie, ale to temat na inny dzień). Na przykład poprawnym kodem będzie następujący kod:

Dim Representation As iRepresentation
Set Representation = New iRepresentation

Debug.Print Representation.Repr

Załóżmy teraz, że mam niestandardowy moduł klasy o nazwie oJigsawPuzzle . Moduł class ma kilka właściwości i metod, ale chcemy mieć taką, która pomoże nam zidentyfikować obiekt JigsawPuzzle, z którym mamy do czynienia po zgłoszeniu błędu. Jednym z oczywistych kandydatów do takiej pracy jest SKU, który jednoznacznie identyfikuje układankę jako produkt na półkach sklepowych. Oczywiście, w zależności od naszej sytuacji, możemy chcieć uwzględnić również inne informacje w naszej reprezentacji.

oJigsawPuzzle.cls

'--== oJigsawPuzzle ==-- class module
Option Compare Database
Option Explicit

Implements iRepresentation   ' <-- We need this line...

Private mSKU As String
Private mPieceCount As Long
Private mDesigner As String
Private mTitle As String
Private mHeightInInches As Double
Private mWidthInInches As Double

'... and these three lines
Private Property Get iRepresentation_Repr() As String
    iRepresentation_Repr = mSKU
End Property

Tu wkracza magia. Gdy pracujemy nad obiektem Variables Inspector, możemy teraz przetestować każdą zmienną obiektu, aby sprawdzić, czy implementuje ten interfejs. A jeśli tak, możemy pobrać tę wartość i zarejestrować ją wraz z resztą naszych wartości zmiennych.

Fragment obsługi błędów

' --== Global Error Handler excerpt ==--

'Include Repr property value for classes that 
'        implement the iRepresentation interface
If TypeOf .Value Is iRepresentation Then
    Dim ObjWithRepr As iRepresentation
    Set ObjWithRepr = .Value
    ThisVar = .Name & ".Repr = " & ObjWithRepr.Repr
End If

I dzięki temu moja łamigłówka dotycząca obsługi błędów jest już gotowa. Wszystkie sztuki są rozliczane. Nie ma śladów ugryzień. Żaden z kawałków się nie rozpada. Nie ma pustych miejsc.

W końcu udało mi się przywrócić porządek w chaosie.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. 5 porad i wskazówek dotyczących Microsoft Access

  2. Ekskluzywny! Dołącz do nas z naszym gościem Michał Bar, kierownik programu dostępu

  3. Tworzenie bazy danych uczniów z Microsoft Access

  4. Jak utworzyć tabelę w widoku projektu w programie Access 2016

  5. Wskazówki dotyczące baz danych dla początkujących