Access
 sql >> база данни >  >> RDS >> Access

Обработка на грешки на ниво завършил

Наслаждавам се на добър пъзел толкова, колкото и на следващия човек. Има нещо удовлетворяващо в това да започнете с купчина привидно произволни парчета и да гледате как картината бавно оживява, докато възстановявате реда в хаоса.

Въпреки това спрях да правя пъзели. Вероятно са минали, о, вече 13 години. Нека направя сметката. Имам четири деца; най-възрастната е на 15.  Да, на две години е точно времето, когато е била достатъчно възрастна, за да се скита до недовършен пъзел, да се укрие с едно от парчетата и да го захрани с кучето, топлинния регистър или тоалетната.

И колкото и удовлетворяващо да е да поставите последното парче в пъзел, толкова съкрушително е да поставите предпоследното парче в пъзела и да осъзнаете, че последното парче липсва.

Така се чувствах за моя код за обработка на грешки.

Инспектор на променливи на vbWatchdog

Ако използвате vbWatchdog за вашата обработка на грешки (трябва), тогава трябва да сте запознати с една от най-мощните му функции:инспектора на променливи. Този обект осигурява достъп до всяка променлива в обхват на всяко ниво на стека на повикванията. Това ниво на детайлност е цифрово злато, когато дойде време за отстраняване на грешки.

През годините разработих усъвършенстван модул за обработка на грешки, който записва цялата тази информация. Докато фино настройвах обработката на грешки, един недостатък започна да се откроява. Макар че можех да извличам стойностите на повечето от моите променливи, всичко, което можех да извлека от обектните променливи, беше или „Нищо“ или „{Object}“.

Това не е почукване на vbWatchdog. Обект може да бъде всичко. Каква друга стойност би могла да покаже? И все пак това липсващо парче от пъзела ме изгриза. Усещах как Вселената ми се смее, когато отстранявах някакъв бъг и ключът към разрешаването му беше скрит зад тази една влудяващо кофти дума „{Object}“.

Само ако имах някакъв начин да знам едно или две от идентифициращите свойства на този обект, бих могъл да разбера какво точно се случва.

Първи опит

Първият ми опит за разрешаване на проблема е инструментът за всеки разочарован програмист:груба сила. В моя глобален манипулатор на грешки добавих Select...Case изявление около .TypeDesc .

Например, имам клас за създаване на SQL, който наричам clsSQL . Едно от свойствата в този клас е .LastSQL . Това свойство съдържа последния SQL израз, който класът е изградил или изпълнил. Може да бъде оператор SELECT или INSERT/UPDATE/DELETE/и т.н. (Взаимствах идеята от обекта DAL на web2py. )

Ето част от моя глобален манипулатор на грешки:

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

С течение на времето започнах да добавям допълнителни персонализирани типове обекти към този списък. С всеки персонализиран тип ще трябва да извличам различно персонализирано свойство.

Имах последното си парче от пъзела. Проблемът е, че го намерих да плува в купата с вода на кучето, цялата сдъвкана от едната страна. Предполагам, че може да се каже, че моят пъзел е завършен, но това беше Пирова победа.

Лечение, което прави повече вреда, отколкото полза

Бързо разбрах, че това решение няма да има мащаб. Имаше много проблеми. Първо, моят глобален код за обработка на грешки щеше да се раздуе. Поддържам кода си за обработка на грешки в един стандартен модул в моята библиотека с кодове. Това означава, че всеки път, когато искам да добавя поддръжка за модул за клас, този код ще бъде добавен към всеки един от моите проекти. Това беше вярно, дори ако модулът клас беше използван само в един проект.

Следващият проблем е, че въвеждах външни зависимости в моя код за обработка на грешки. Ами ако смених моя clsSQL клас някой ден и преименувайте или премахнете .LastSQL метод? Какви са шансовете да разбера, че такава зависимост е съществувала, докато работех в моя clsSQL клас? Този подход бързо би рухнал под собствената си тежест, освен ако не измисля алтернатива.

Търсим Python за решение

Разбрах, че това, което наистина исках, е някакъв начин да определя канонично представяне на обект отвътре този обект . Исках да мога да реализирам това представяне толкова просто или сложно, колкото е необходимо. Исках начин да гарантирам, че няма да се взриви по време на изпълнение. Исках да е напълно незадължителен за всеки модул на класа.

Това изглежда като дълъг списък с желания, но успях да удовлетворя всеки елемент от него с решението, което намерих.

За пореден път взаимствах идея от Python. Всички обекти на Python имат специално свойство, известно като ._repr . Това свойство е низовото представяне на обекта. По подразбиране той ще върне името на типа и адреса на паметта на екземпляра на обекта. Програмистите на Python обаче могат да дефинират .__repr__ метод за отмяна на поведението по подразбиране. Това е сочно нещо, което исках за моите VBA класове.

Най-накрая намерих идеалното си решение. За съжаление го намерих на друг език, където решението всъщност е характеристика на самия език . Как това трябва да ми помогне във VBA? Оказва се, че идеята е важна част; Просто трябваше да бъда малко креативен с внедряването.

Интерфейси за спасяване

За да пренеса тази концепция на Python във VBA, се обърнах към една рядко използвана функция на езика:интерфейси и оператор TypeOf. Ето как работи.

Създадох модул за клас, който нарекох iRepresentation . Интерфейсите в повечето езици са наречени с водещо "i" по конвенция. Разбира се, можете да назовете модулите си както искате. Ето пълния код за моето iRepresentation клас.

iRepresentation.cls

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

Public Property Get Repr() As String
End Property

Трябва да отбележа, че няма нищо особено в модул за клас, който служи като интерфейс във VBA. С това имам предвид, че няма ключова дума на ниво модул или скрит атрибут, който трябва да зададем. Можем дори да инстанцираме нов обект, използвайки този тип, макар че няма да има много смисъл (едно изключение е тестването, но това е тема за различен ден). Например, следният би бил валиден код:

Dim Representation As iRepresentation
Set Representation = New iRepresentation

Debug.Print Representation.Repr

Сега да кажем, че имам персонализиран модул за клас с име oJigsawPuzzle . Модулът на класа има няколко свойства и методи, но ние искаме такъв, който да ни помогне да идентифицираме с кой обект JigsawPuzzle имаме работа, когато се появи грешка. Един очевиден кандидат за такава работа е SKU, който уникално идентифицира пъзела като продукт на рафтовете на магазините. Разбира се, в зависимост от нашата ситуация, може да искаме да включим и друга информация в нашето представяне.

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

Ето къде идва магията.  Когато си проправяме път през обекта на инспектора на променливи, сега можем да тестваме всяка променлива на обекта, за да видим дали прилага този интерфейс. И ако е така, можем да вземем тази стойност и да я регистрираме заедно с останалите стойности на нашите променливи.

Откъс от манипулатора на грешки

' --== 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

И с това моят пъзел за обработка на грешки вече е завършен. Всички парчета се отчитат. Няма следи от ухапване. Нито едно от парчетата не се отлепва. Няма празни места.

Най-накрая възстанових реда в хаоса.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Какви са ограниченията на MS Access?

  2. Какво е заявка за база данни?

  3. Статични функции и подп

  4. Характеристики на доклад

  5. Оценяване, когато се оценява израз в заявка