Гость
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / Обработка ошибок / 5 сообщений из 5, страница 1 из 1
07.11.2018, 21:06
    #39729579
Lekks
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обработка ошибок
Уважаемые знатоки! ))) Посмотрите, пожалуйста код, на предмет необходимости обработки ошибок, поскольку я с данным вопросом что-то пока не разобрался. Не пойму, где нужна, а где можно без этого обойтись. Не буду против конструктивной критики самого кода))))

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
Option Compare Database

Option Explicit

Private Sub BirthDate_GotFocus()
Me.BirthDate.SelStart = 0
End Sub

Private Sub CancCmd_Click()
    Me.Undo
    Me.Position.Value = Null
    Me.Rank.Value = Null
End Sub

Private Sub CloCmd_Click()
    Me.Undo
    Me.Position.Value = Null
    Me.Rank.Value = Null
    DoCmd.Close acForm, "FnewPeopleRst"
End Sub

Private Sub Form_BeforeUpdate(Cancel As Integer)
  Dim rstPR As ADODB.Recordset
 On Error GoTo ExitHere
    If IsNull(Me.FName) Or IsNull(Me.LName) Or IsNull(Me.PName) Then
        MsgBox "Не заполнены обязательные сведения (Фамилия/Имя/Отчество)", vbOKOnly + vbCritical, "НЕДОСТАТОЧНО ДАННЫХ"
        Cancel = True
    ElseIf DCount("*", "People", "(People.FName & People.LName & People.PName)='" & (Me.FName & Me.LName & Me.PName) & "'") > 0 Then
        MsgBox "Данный человек имеется в базе", vbOKOnly + vbCritical, "ДУБЛИКАТ ДАННЫХ"
        Me.Undo
    ElseIf PeopleSt.Value = 0 And (IsNull(Me.Position) Or IsNull(Me.Rank)) Then
        MsgBox "Не заполнены сведения о сотруднике (Должность/Звание)", vbOKOnly + vbCritical, "НЕДОСТАТОЧНО ДАННЫХ"
        Cancel = True
    ElseIf vbNo = MsgBox("Вы хотите сохранить новые данные?", vbYesNo + vbQuestion, "ОБНАРУЖЕН НОВЫЙ НАРУШИТЕЛЬ/СОТРУДНИК") Then
            Me.Undo
            Me.Position.Value = Null
            Me.Rank.Value = Null
    Else
      If PeopleSt.Value = 0 Then
        Set rstPR = New ADODB.Recordset
         With rstPR
            .Open "Officers", CurrentProject.Connection, adOpenDynamic, adLockPessimistic
            .AddNew
            .Fields("PeID") = Me.PeopleID
            .Fields("Position") = Me.Position
            .Fields("Rank") = Me.Rank
            .Update
         End With
        rstPR.Close
        Set rstPR = Nothing
        Me.Position.Value = Null
        Me.Rank.Value = Null
       Else: DoCmd.GoToRecord , , acNewRec
       End If
    End If
ExitHere:
    Exit Sub
End Sub

Private Sub Form_Load()
    PeopleSt.Value = -1
    DoCmd.MoveSize Height:=2500
    DoCmd.GoToRecord , , acNewRec
    Me.Position.ColumnCount = 2
    Me.Position.ColumnWidths = "0;50"
    Me.Position.RowSource = "SELECT * FROM Positions ORDER BY PositID"
    Me.Rank.ColumnCount = 2
    Me.Rank.ColumnWidths = "0;50"
    Me.Rank.RowSource = "SELECT * FROM Ranks ORDER BY RankID"
End Sub

Private Sub PeopleSt_Click()
    If PeopleSt.Value = 0 Then
            DoCmd.MoveSize Height:=5800
            Me.BirthDate.Visible = False
        Else
            DoCmd.MoveSize Height:=2500
            Me.BirthDate.Visible = True
        End If
End Sub

Private Sub SaveCmd_Click()
    On Error GoTo ExitHere
     DoCmd.GoToRecord , , acNewRec
ExitHere:
    Exit Sub
End Sub

...
Рейтинг: 0 / 0
08.11.2018, 09:15
    #39729756
Joss
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обработка ошибок
Поставь себе надстройку MZTools и там обработчик ошибок ставится нажатием одной кнопки. Ставь везде и не парься рассуждениями надо-не надо. Раз затрудняешься определить, то ставь.
...
Рейтинг: 0 / 0
08.11.2018, 10:01
    #39729783
MrShin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обработка ошибок
Так у вас практически никакой обработки ошибок и нет - пользователь не увидит никакого сообщения об ошибке и не сможет ничего сообщить разработчику, он даже скорее всего не поймет, что что-то не работает.
Обработчики нужны во всех процедурах, которые вызываются системой (события), иначе при ошибке возникнет необработанная ошибка и пользователя может выкинуть в код, это недопустимо. Поцедуры, которые вызываются из кода могут и не иметь обработчика, ошибка будет передана в вызывающую процедуру, но при этом код и текст ошибки не будут соответствовать той линии кода, где ошибка действительно возникла, остановка будет на вызове процедуры без обработчика и сообщение об ошибки будет весьма невнятным.

Еще момент - обработчик ошибок должен проводить финальные операции типа закрытия рекордсетов или разрушения переменных даже при возникновении ошибок, иначе это может привести к нестабильности системы.

Я использую два типа обработчиков, каждый имеет несколько модификаций, но это не принципиально. Первый тип - для событий и кода, который непосредственно взаимодествует с пользователем

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
Private Sub cmdConfirm_Click()
    Dim rst As DAO.Recordset
    On Error GoTo ErrorHandler
    
    DoCmd.Hourglass True
    Set rst = dbLocal.OpenRecordset("qryReport")
    With rst
        While Not .EOF
            
            'делаем что-то
            Call MyFunction
            .MoveNext
        Wend
    End With
ExitHere:
    On Error Resume Next
    ' курсор будет нормальным и рекордсет закрыт даже в случае ошибки
    DoCmd.Hourglass False
    rst.Close
    Set rst = Nothing

    Exit Sub
    'следующая команда никогда не выполняется автоматически, но нужна для удобства отладки:
    'когда появляется сообщение об ошибке, нажимаем Ctrl-Break, переходим в отладчик, Ctrl-Shift-F8 для возврата из LogError
    'затем ставим курсор на Resume, Ctrl-F9 для перемещения указателя выполнения на Resume, и по F8 попадаем точно на инструкцию с ошибкой. Можно исправить и повторить попытку заново без перезапуска процедуры
    Resume '>> remove in release
ErrorHandler:
    'эта функция записывает ошибку в базу и выводит сообщение для пользователя
    LogError Err.Number, Err.Description, Erl, "cmdConfirm_Click", "Form_frm_InputDialog"
    Resume ExitHere
End Sub



Второй тип - для процедур, вызываемых из кода:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
Public Function MyFunction()
10        On Error GoTo ErrorHandler
          ' делаем что-то
ExitHere:
20        Exit Function
30        Resume '>> remove in release
ErrorHandler:
40        Debug.Assert Not (STOP_AT_ERROR And IS_DEV) '>> remove in release
50        Err.Raise Err.Number, "MyFunction of Form_frm_InputDialog", Err.Description & vbCrLf & "in MyFunction of Form_frm_InputDialog at " & Erl
End Function


Здесь задача обработчика - добавить к описанию ошибки информацию о процедуре и линии, где возникла ошибка, новое описание передается в вызвавшую процедуру. В результате, если в вызвавшей процедуре будет обработчик первого типа, то появится сообщение со теком вызова процедур, что поможет определить причину гораздо проще.

Debug.Assert в обработчике второго типа нужен для отладки - если обе булевские глобальные константы STOP_AT_ERROR и IS_DEV (определены в стандартном модуле) установлены в True, то код остановится в этом месте в случае возникновения ошибки без возврата в вызывающую процедуру, что позволит очень легко найти строку с ошибкой с помощью Resume, проанализировать переменные, при необходимости исправить код и повторить выполнение без перезапуска процедуры.

Есть модификация обработчика второго типа с финальной секцией для закрытия курсоров и т.п.:
Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
Public Function MyFunction()
    On Error GoTo ErrorHandler
    ' делаем что-то

ExitHere:
    On Error Resume Next
    'сюда пишем финализирующие команды, которые должны выполняться всегда
    Dim err_num As Long, err_descr As String, err_ln As String
    If Len(err_descr) > 0 Then GoTo ErrorRaise
    Exit Function
    Resume '>> remove in release
ErrorHandler:
    err_num = Err.Number: err_descr = Err.Description: err_ln = Erl
    Debug.Assert Not (STOP_AT_ERROR And IS_DEV) '>> remove in release
    Resume ExitHere
ErrorRaise: On Error GoTo 0
    Err.Raise err_num, "MyFunction of Form_frm_InputDialog", err_descr & vbCrLf & "in MyFunction of Form_frm_InputDialog at " & err_ln
End Function


Я также всегда нумерую строки кода, чтобы в сообщении об ошибке выводился номер строки, где возникла ошибка.
Для генерации обработчиков и нумерации использую MZ-Tools, очень удобный инструмент, не представляю без него нормальной работы. Обработчики и нумерация есть и в бесплатной 3-й версии, но 8-я намного удобнее, я ее даже купил, хотя можно постоянно сбрасывать пробный месячный период.

Текст LogError:

Код: vbnet
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
Option Compare Database
Option Explicit

'// module with error handling functions
    ' Purpose: Generic error handler.
    ' Logs errors to table "ErrorLog".
    ' Arguments: lngErrNumber - value of Err.Number
    ' strErrDescription - value of err.description
    ' strLine - code line number (Erl) Erl=0 if no row number in the line
    ' strCallingProc - name of sub|function that generated the error.
    ' strCallingModule - name of code module that generated the error.
    ' vParameters - optional string: List of parameters to record.
    ' bShowUser - optional boolean: If False, suppresses display.
Function LogError(ByVal lngErrNumber As Long, ByVal strErrDescription As String, strLine As String, _
                  strCallingProc As String, Optional strCallingModule As String, Optional vParameters = "{Missing}", Optional bShowUser As Boolean = True) As Boolean
    On Error GoTo Err_LogError
    Dim strMsg As String                              ' String for display in MsgBox
    Dim rst    As DAO.Recordset                       ' The Aph_tblErrorLog table
    Select Case lngErrNumber
        Case 0
            Debug.Print strCallingProc & " called error 0."
        Case 2501                                     ' Cancelled
            'Do nothing.
'        Case 3314, 2101, 2115                         ' Can't save.
'            If bShowUser Then
'                strMsg = "Record cannot be saved at this time." & vbCrLf & "Complete the entry, or press <Esc> to undo."
'                MsgBox strMsg, vbExclamation, "Error"
'            End If
        Case Else
            If bShowUser Then
                strMsg = "Error " & lngErrNumber & ": " & strErrDescription & vbCrLf & "in " & _
                strCallingProc & " of " & strCallingModule & " at " & strLine
                Interaction.MsgBox strMsg, vbExclamation, "Error " & Now()
            End If
            'log the error to database
            Set rst = CurrentDb.OpenRecordset("tbl_BMS_ErrorLog", , dbAppendOnly)
            rst.AddNew
            rst![ErrorNum] = lngErrNumber
            rst![ErrorDescription] = Left$(strErrDescription, 255)
            rst![ErrLine] = strLine
            rst![CallingProc] = strCallingProc
            rst![Module] = strCallingModule
            rst![CreatedTimeStamp] = Now()
            rst![UserName] = GetCurrentUserID()
            If Not IsMissing(vParameters) Then
                rst![Parameters] = Left(vParameters, 255)
            End If
            rst.Update
            rst.Close
            LogError = True
    End Select

Exit_LogError:
    Set rst = Nothing
    Exit Function
Err_LogError:
    strMsg = "An unexpected situation arose in your program." & vbCrLf & _
             "Please write down the following details:" & vbCrLf & vbCrLf & _
             "Calling Proc: " & strCallingProc & vbCrLf & _
             "Error Number " & lngErrNumber & " in line " & strLine & vbCrLf & strErrDescription & vbCrLf & vbCrLf & _
             "Unable to record because Error " & Err.Number & " in line " & Erl & vbCrLf & Err.Description
    Interaction.MsgBox strMsg, vbCritical, "LogError()"
    Resume Exit_LogError
End Function


...
Рейтинг: 0 / 0
08.11.2018, 10:03
    #39729787
MrShin
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обработка ошибок
Забыл добавить номера строк в 2 примера. Они должны быть в продакшне и тесте.
...
Рейтинг: 0 / 0
08.11.2018, 17:00
    #39730047
Lekks
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
Обработка ошибок
MrShinТак у вас практически никакой обработки ошибок и нет

Lekks... поскольку я с данным вопросом что-то пока не разобрался... ))))

JossСтавь везде и не парься рассуждениями надо-не надо.

Так и поступлю))) Пойду MZTools качать))) Спасибо!
...
Рейтинг: 0 / 0
Форумы / Microsoft Access [игнор отключен] [закрыт для гостей] / Обработка ошибок / 5 сообщений из 5, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]