Bestimmte ODBC-Fehler in der OnError-Eigenschaft eines Formulars können nicht abfangen (KB-206175)

Gilt für
Access für Microsoft 365 Access 2021 Access 2019 Access 2016

Wenn Sie die OnError-Eigenschaft eines Access-Formulars auf eine Ereignisprozedur festlegen, können Sie die Beschreibung eines ODBC-Fehlers in dieser Prozedur nicht abrufen und auch keinen bestimmten ODBC-Fehler abfangen. Wenn ein ODBC-Fehler auftritt, ist die einzige Information, die an die Error-Ereignisprozedur übergeben wird, die Nummer eines generischen Fehlers, z. B. 3146, der der Fehlermeldung entspricht: ODBC-Call fehlgeschlagen.

Ursache

ODBC-Fehlermeldungen bestehen normalerweise aus zwei Komponenten. Die erste Komponente ist Fehler 3146, deren Beschreibung wie folgt lautet:

Fehler beim ODBC-Aufruf

Die serverspezifischen Fehlerinformationen sind in der zweiten Komponente enthalten, aus der Sie eine Fehlernummer und eine Beschreibung wie die folgenden abrufen können:

[Microsoft][ODBC SQL Server Driver][SQL Server] <Serverspezifische Fehlermeldung> (#<Fehlernummer>)

Wenn Sie die OnError-Eigenschaft eines Formulars auf eine Ereignisprozedur festlegen, können Sie die Nummer der ersten Komponente des Fehlers abfangen, aber Sie können die Anzahl der zweiten Komponente nicht abfangen. Die serverspezifischen Informationen im zweiten Teil des ODBC-Fehlers werden auf dem Bildschirm angezeigt, nachdem die Ausführung des Codes abgeschlossen wurde, es sei denn, Sie fügen die folgende Zeile in die Ereignisprozedur ein:

Response = acDataErrContinue

Lösung

Hinweis

Microsoft stellt Programmierbeispiele nur zur Veranschaulichung zur Verfügung, ohne ausdrückliche oder stillschweigende Garantie. Dies schließt die stillschweigende Gewährleistung der Marktgängigkeit oder der Eignung für einen bestimmten Zweck ein, ist aber nicht darauf beschränkt. In diesem Artikel wird davon ausgegangen, dass Sie mit der vorgestellten Programmiersprache und den Werkzeugen zum Erstellen und Debuggen von Prozeduren vertraut sind. Die Microsoft Support-Spezialisten können bei der Erläuterung der Funktionalität bestimmter Prozeduren helfen, jedoch werden sie diese Beispiele nicht in Bezug auf eine erweiterte Funktionalität verändern, noch werden sie Prozeduren entwickeln, die auf Ihre besonderen Bedürfnisse zugeschnitten sind.

Sie können eine Microsoft Visual Basic for Applications-Prozedur erstellen, die Datenzugriffsobjekte (Data Access Objects, DAO) verwendet, um ein RecordsetClone-Objekt zu aktualisieren, das auf dem Formular basiert. Auf diese Weise können Sie alle fehlermeldungen, die Sie erhalten, abfangen.

DAO enthält eine Errors-Auflistung , mit der Sie die serverspezifischen Informationen im zweiten Teil des ODBC-Fehlers abfangen können. Wenn ein ODBC-Fehler auftritt, wird die erste Komponente im ersten Element der Errors-Auflistung und die zweite Komponente im zweiten Element gespeichert.

Im Beispiel in diesem Artikel wird das BeforeUpdate-Ereignis anstelle des Error-Ereignisses verwendet, um bestimmte ODBC-Fehler abzufangen. Führen Sie die folgenden Schritte aus, um eine Funktion zu erstellen, die bestimmte ODBC-Fehler abfangen kann, wenn das BeforeUpdate-Ereignis eines Formulars auftritt:

  1. Erstellen Sie eine leere Desktopdatenbank.

  2. Link zur dbo_Accounts Tabelle in der AdventureWorks-Beispieldatenbank in Microsoft SQL Server.

  3. Verwenden Sie den Formular-Assistenten – Spaltenbasiertes Layout, um ein neues Formular basierend auf der Kontentabelle zu erstellen.

  4. Speichern Sie das Formular als frmAccounts.

  5. Erstellen Sie ein neues Modul, und geben Sie dann die folgende Zeile im Abschnitt Deklarationen ein, wenn diese Zeile noch nicht vorhanden ist:
    Option Explicit

  6. Geben Sie die folgende Prozedur in das Modul ein, oder fügen Sie sie ein:

    Public Function SaveRecODBC(SRO_form As Form) As Boolean
    ' ***************************************************************
    ' Function: SaveRecODBC
    ' Purpose: Updates a form based on a linked ODBC table
    ' and traps any ODBC errors.
    ' Arguments: SRO_Form, which refers to the form.
    ' Returns: True if successful or False if an error occurs.
    ' ***************************************************************
    On Error GoTo SaveRecODBCErr
    Dim fld As Field, ctl As Control
    Dim errStored As Error
    Dim rc As DAO.Recordset
    
    ' Check to see if the record has changed.
    If SRO_form.Dirty Then
        Set rc = SRO_form.Recordset.Clone
        If SRO_form.NewRecord Then
            rc.AddNew
            For Each ctl In SRO_form.Controls
                ' Check to see if it is the type of control
                ' that has a ControlSource.
                If ctl.ControlType = acTextBox Or _
                    ctl.ControlType = acComboBox Or _
                    ctl.ControlType = acListBox Or _
                    ctl.ControlType = acCheckBox Then
                    ' Verify that a value exists in the ControlSource.
                    If ctl.Properties("ControlSource") <> "" Then
                        ' Loop through the fields collection in the
                        ' RecordsetClone. If you find a field name
                        ' that matches the ControlSource, update the
                        ' field. If not, skip the field. This is
                        ' necessary to account for calculated controls.
                        For Each fld In rc.Fields
                            ' Find the field and verify
                            ' that it is not Null.
                            ' If it is Null, don't add it.
                            If fld.Name = ctl.Properties("ControlSource") _
                            And Not IsNull(ctl) Then
                                fld.Value = ctl
                                ' Exit the For loop
                                ' if you have a match.
                                Exit For
                            End If
                        Next fld
                    End If ' End If ctl.Properties("ControlSource")
                End If ' End If ctl.controltype
            Next ctl
            rc.Update
        Else
            ' This is not a new record.
            ' Set the bookmark to synchronize the record in the
            ' RecordsetClone with the record in the form.
            rc.Bookmark = SRO_form.Bookmark
            rc.Edit
            For Each ctl In SRO_form.Controls
                ' Check to see if it is the type of control
                ' that has a ControlSource.
                If ctl.ControlType = acTextBox Or _
                    ctl.ControlType = acComboBox Or _
                    ctl.ControlType = acListBox Or _
                    ctl.ControlType = acCheckBox Then
                    ' Verify that a value exists in the
                    ' ControlSource.
                    If ctl.Properties("ControlSource") <> "" Then
                        ' Loop through the fields collection in the
                        ' RecordsetClone. If you find a field name
                        ' that matches the ControlSource, update the
                        ' field. If not, skip the field. This is
                        ' necessary to account for calcualted controls.
                        For Each fld In rc.Fields
                            ' Find the field and make sure that the
                            ' value has changed. If it has not
                            ' changed, do not perform the update.
                            If fld.Name = ctl.Properties("ControlSource") _
                                And fld.Value <> ctl And _
                                Not IsNull(fld.Value <> ctl) Then
                                fld.Value = ctl
                                ' Exit the For loop if you have a match.
                                Exit For
                            End If
                        Next fld
                    End If ' End If ctl.Properties("ControlSource")
                End If ' End If ctl.controltype
            Next ctl
            rc.Update
        End If ' End If SRO_form.NewRecord
    End If ' End If SRO_form.Dirty
    ' If function has executed successfully to this point then
    ' set its value to True and exit.
    SaveRecODBC = True
    
    Exit_SaveRecODBCErr:
        Exit Function
    
    SaveRecODBCErr:
    ' The function failed because of an ODBC error.
    ' Below are a list of some of the known error numbers.
    ' If you are not receiving an error in this list,
    ' add that error to the Select Case statement.
    For Each errStored In DBEngine.Errors
        Select Case errStored.Number
            Case 3146 ' No action -- standard ODBC--Call failed error.
            Case 2627 ' Error caused by duplicate value in primary key.
                MsgBox "You tried to enter a duplicate value in the Primary Key."
            Case 3621 ' No action -- standard ODBC command aborted error.
            Case 547 ' Foreign key constraint error.
                MsgBox "You violated a foreign key constraint."
            Case Else ' An error not accounted for in the Select Case ' statement.
                On Error GoTo 0
                Resume
        End Select
    Next errStored
    SaveRecODBC = False
    Resume Exit_SaveRecODBCErr
    
    End Function
    
    
  7. Speichern Sie das Modul mit einem eindeutigen Namen, und schließen Sie das Modulfenster.

  8. Legen Sie die BeforeUpdate-Eigenschaft des FrmAccounts-Formulars auf die folgende Ereignisprozedur fest:

    Private Sub Form_BeforeUpdate(Cancel As Integer)
    ' If you can save the changes to the record undo the changes on the form.
    If SaveRecODBC(Me) Then Me.Undo
    ' If this is a new record go to the last record on the form.
    If Me.NewRecord Then
        RunCommand acCmdRecordsGoToLast
    Else
        ' If you can't update the record, cancel the BeforeUpdate event.
        Cancel = -1
    End If
    End Sub
    
    
  9. Klicken Sie im Menü Debuggen auf Name ihrer Datenbank> kompilieren<.

  10. Wenn keine Fehler auftreten, speichern Sie das Formular.

  11. Öffnen Sie das Formular frmAccounts, und fügen Sie dann einen neuen Datensatz hinzu, oder bearbeiten Sie einen Datensatz.
    Wenn Sie eine Änderung an einem Datensatz vornehmen, wird der Datensatz gespeichert, wenn Sie zu einem anderen Datensatz wechseln. Wenn ein ODBC-Fehler auftritt, wird die benutzerdefinierte Meldung angezeigt, die auf dem serverspezifischen Fehler basiert, und die generische Meldung "ODBC--call failed" wird abgefangen.