Zur Hauptseite ... Zum Onlinearchiv ... Zum Abonnement ... Zum Newsletter ... Zu den Tools ... Zum Impressum ... Zum Login ...

Gedrucktes Heft

Diesen Beitrag finden Sie in Ausgabe 4/2018.

Unser Angebot für Sie!

Lesen Sie diesen Beitrag und 500 andere sofort im Onlinearchiv, und erhalten Sie alle zwei Monate brandheißes Access-Know-how auf 72 gedruckten Seiten! Plus attraktive Präsente, zum Beispiel das bald erscheinende Buch 'Access 2010 - Das Grundlagenbuch für Entwickler'!

Diesen Beitrag twittern

Löschen von in Beziehung stehenden Daten

Wenn Sie die Beziehung zwischen zwei Tabellen festlegen, haben Sie die Möglichkeit, referenzielle Integrität für die Daten zu definieren. Ist dies geschehen, legen Sie mit der Option Löschweitergabe auch noch fest, ob verknüpfte Daten beim Löschen von Datensätzen auf der einen Seite der Beziehung ebenfalls gelöscht werden sollen. Wenn Sie solche Daten in Formularen löschen, erhalten Sie unter Umständen Systemmeldungen, die für den Endnutzer der Anwendung nur wenig Aussagekraft haben. Dieser Beitrag zeigt, wie Sie mit dem Löschen von in Beziehung stehenden Daten umgehen können.

Unsere Südsturm-Beispieldatenbank liefert ausreichend Tabellen und Beziehungen, um die verschiedenen Konstellationen des Einsatzes der Löschweitergabe oder eben des Weglassens der Löschweitergabe zu beurteilen.

Löschweitergabe oder nicht?

Wie und wo wirkt die Löschweitergabe eigentlich? In der Beziehung zwischen Kunden und Anreden sind diese nicht definiert (siehe Bild 1).

Anlegen einer Beziehung mit referenzieller Integrität, aber ohne Löschweitergabe

Bild 1: Anlegen einer Beziehung mit referenzieller Integrität, aber ohne Löschweitergabe

Dies sorgt dafür, dass Sie in einer 1:n-Beziehung zwischen einer Kunden- und einer Anreden-Tabelle zwar Kunden löschen können, ohne dass die Datensätze der Anreden-Tabelle davon berührt werden. Sie können aber keine Anreden löschen, die bereits mindestens einem Kunden zugeordnet wurden. Wenn Sie dies dennoch versuchen, erhalten Sie etwa in der Datenblattansicht die Meldung aus Bild 2.

Ohne Löschweitergabe werden verknüpfte Datensätze auf der n-Seite der Beziehung geschützt.

Bild 2: Ohne Löschweitergabe werden verknüpfte Datensätze auf der n-Seite der Beziehung geschützt.

Wenn hier nun die Option Löschweitergabe aktiviert wäre, würde das Löschen einer Anrede dazu führen, dass auch alle damit verknüpften Kunden-Datensätze gelöscht würden – und das wäre einigermaßen fatal. Deshalb sollten Sie die Löschweitergabe nicht einfach so festlegen.

Eine Stelle, an der die Löschweitergabe sinnvoll ist, ist etwa die Beziehung von Kunden und Bestellungen. Wenn ein Kunde Sie auffordert, alle Kundendaten zu löschen, sind davon natürlich auch die Bestellungsdaten betroffen – Sie können ja keinen Datensatz in der Tabelle tblBestellungen behalten, ohne dass dieser einem Kunden zugeordnet ist. Wir gehen an dieser Stelle davon aus, dass Sie die Kunden- und Bestelldaten tatsächlich nicht mehr benötigen und diese löschen können. In diesem Fall legen Sie für die Beziehung zwischen den Tabellen tblKunden und tblBestellungen die Eigenschaft Löschweitergabe an verwandte Datensätze fest (siehe Bild 3).

Löschweitergabe zwischen Kunden und Bestellungen

Bild 3: Löschweitergabe zwischen Kunden und Bestellungen

Ist dies der Fall und die Option Client­einstellungen|Be­ar­beiten|Bestätigen|Datensatzänderungen in den Access-Optionen ist aktiviert, erhalten Sie vor dem Löschen eines Kunden-Datensatzes, dem bereits Bestelldatensätze zugeordnet sind, die Meldung aus Bild 4.

Bei aktiver Löschweitergabe erscheint mit Standardoptionen diese Meldung beim Versuch, einen Datensatz mit verknüpften Daten zu löschen.

Bild 4: Bei aktiver Löschweitergabe erscheint mit Standardoptionen diese Meldung beim Versuch, einen Datensatz mit verknüpften Daten zu löschen.

Wie Sie solche Meldungen durch eigene Meldungen ersetzen, können Sie im Beitrag Löschen in Formularen: Ereignisse nachlesen (www.access-im-unternehmen.de/1128). Wir schauen uns nun an, wie Sie die Meldungen, die beim Fehlschlagen des Löschvorgangs von Datensätzen ohne Löschweitergabe erscheinen, durch eine selbst definierte Meldung ersetzen können.

Eigene Meldung bei gescheitertem Löschen

Die obige Meldung Der Datensatz kann nicht gelöscht oder geändert werden, da die Tabelle "tblKunden" in Beziehung stehende Datensätze enthält können Sie nicht so einfach deaktivieren – auch nicht, wenn Sie die Access-Option Clienteinstellungen|Bearbeiten|Bestäti­gen|Daten­satzänderungen deaktivieren.

Es gibt auch scheinbar keine Möglichkeit, per VBA in den Aufruf dieser Meldung einzugreifen – was auch logisch scheint, dann die Meldung kann ja auch komplett über die Benutzeroberfläche ausgelöst werden.

Die einzige Möglichkeit, hier einzugreifen, wird klar, wenn Sie diese Hinweismeldung anders interpretieren – nämlich als Fehlermeldung! Dennoch bleibt die Frage: Wo können wir eine Fehlermeldung unterbinden, die gar nicht per VBA ausgelöst wird? Die Lösung ist nicht leicht zu erraten, aber letztlich doch einfach.

Erstens gelingt dies ausschließlich in Formularen und nicht in der Datenblattansicht von Tabellen oder Abfragen. Zweitens erledigen wir das mit der Ereignisprozedur, die durch das Ereignis Bei Fehler des Formulars ausgelöst wird.

Für das Beispiel entfernen wir nun zunächst den Haken bei der Option Löschweitergabe an verwandte Datensätze der Beziehung zwischen den Tabellen tblKunden und tblBestellungen. Damit sorgen wir also dafür, dass die oben erwähnte Meldung wieder erscheint statt der Rückfrage, ob die verknüpften Datensätze mitgelöscht werden sollen (siehe Bild 5).

Entfernen der Löschweitergabe

Bild 5: Entfernen der Löschweitergabe

In einem Beispielformular, das einfach die Tabelle tblKunden mit allen Feldern im Detailbereich und dem Wert Datenblatt für die Eigenschaft Standardansicht verwendet (siehe Bild 6), wollen wir den Einsatz der Ereignisprozedur Bei Fehler demonstrieren.

Entwurf des Beispielformulars

Bild 6: Entwurf des Beispielformulars

Dazu stellen wir den Wert der Eigenschaft Bei Fehler des Formulars auf [Ereignisprozedur] ein und klicken auf die Schaltfläche mit den drei Punkten. Die so im VBA-Editor automatisch angelegte Ereignisprozedur ergänzen wir mit folgender MsgBox-Anweisung:

Private Sub Form_Error(DataErr As Integer,  Response As Integer)
     MsgBox DataErr
End Sub

Wenn wir nun einen Datensatz aus diesem Formular löschen, erscheint die Fehlermeldung aus Bild 7. Damit können wir arbeiten: Wir kennen nun die Nummer des Fehlers und können auf diesen reagieren.

Fehlermeldung durch das Ereignis Bei Fehler

Bild 7: Fehlermeldung durch das Ereignis Bei Fehler

Wenn Sie auch noch die Fehlermeldung haben wollen, erhalten Sie diese mit folgender MsgBox-Anweisung (siehe Bild 8):

Text der Fehlermeldung

Bild 8: Text der Fehlermeldung

MsgBox AccessError(DataErr)

Die vom System erzeugte Meldung wird allerdings immer noch nach der Ausgabe unserer eigenen Meldung nachgereicht. Dies können wir verhindern, indem wir die folgende Anweisung hinzufügen und damit den Parameter Response auf den Wert acDataErrorContinue einstellen:

Private Sub Form_Error(DataErr As Integer, Response As Integer)
     MsgBox DataErr
     Response = acDataErrContinue
End Sub

Verknüpfte Daten auf Benutzerwunsch löschen

Was aber tun wir nun, wenn wir dem Benutzer die Wahl lassen wollen, die mit dem zu löschenden Datensatz verknüpften Daten, die das Löschen verhindern, ebenfalls zu löschen? In diesem Fall ermitteln wir zunächst die Fehlernummer für diesen Fall und prüfen, ob es sich dabei um die erwartete Nummer handelt – in diesem Fall die Nummer 3200. Diese Prüfung führen wir in einer Select Case-Bedingung wie in Listing 1 aus.

Private Sub Form_Error(DataErr As Integer, Response As Integer)
     Dim db As DAO.Database
     Dim intResponse As VbMsgBoxResult
     Dim lngAnzahl As Long
     Dim lngKundeID As Long
     Select Case DataErr
         Case 3200
             lngKundeID = Me!KundeID
             lngAnzahl = DCount("*", "tblBestellungen", "KundeID = " & lngKundeID)
             intResponse = MsgBox("Dieser Datensatz enthält " & lngAnzahl & " verknüpfte Bestellungen. " _
                 & "Soll der Kunde mit diesen Bestellungen gelöscht werden?", vbYesNo + vbExclamation, "Löschbestätigung")
             If intResponse = vbYes Then
                 Set db = CurrentDb
                 db.Execute "DELETE FROM tblBestellungen WHERE KundeID = " & lngKundeID, dbFailOnError
                 db.Execute "DELETE FROM tblKunden WHERE KundeID = " & lngKundeID, dbFailOnError
             End If
             Response = acDataErrContinue
     End Select
End Sub

Listing 1: Löschen verknüpfter Daten trotz deaktivierter Löschweitergabe

Diese ermittelt zunächst die ID des beim Anklicken der Entfernen-Taste markierten Kunden und speichert diese in der Variablen lngKundeID. Die folgende Anweisung ermittelt die zweifelsohne vorhandenen verknüpften Datensätze aus der Tabelle tblBestellungen – wenn keine Bestellungen mit dem Kunden verknüpft wären, würde ja dieser Fehler nicht ausgelöst werden –, und speichert diese Anzahl in der Variablen lngAnzahl. Das Ergebnis der folgenden MsgBox-Funktion, die den Benutzer fragt, ob der Kunde samt den verknüpften Bestellungen gelöscht werden soll (siehe Bild 9), landet in der Variablen intResponse des Typs VbMsgBoxResult. Enthält diese anschließend den Wert vbYes, wollen wir die verknüpften Datensätze aus der Tabelle tblBestellungen löschen. Danach können wir dann auch ohne Verletzungen der referenziellen Integrität den Kundendatensatz löschen. Schließlich folgt auch hier wieder die Angabe des Wertes acDataErrContinue für den Parameter Response.

Meldung beim Versuch, einen Kundendatensatz mit verknüpften Bestelldatensätzen zu löschen

Bild 9: Meldung beim Versuch, einen Kundendatensatz mit verknüpften Bestelldatensätzen zu löschen

Leider wird der so gelöschte Datensatz im Formular nur als gelöscht markiert, aber nicht aus der Liste entfernt (siehe Bild 10). Das geschieht erst nach dem Aktualisieren. Aber das sollte ja kein Problem sein – wir fügen einfach die Requery-Methode zur Prozedur Form_Error hinzu:

Der Datensatz wird als gelöscht markiert, aber die Zeile verschwindet nicht.

Bild 10: Der Datensatz wird als gelöscht markiert, aber die Zeile verschwindet nicht.

Private Sub Form_Error(...)
     ...
     Select Case DataErr
         Case 3200
             ...
             Me.Requery
     End Select
End Sub

Wenn wir nun erneut einen der Datensätze löschen, erhalten wir allerdings die Fehlermeldung aus Bild 11. Offensichtlich fasst Access die Datenoperationen beim Löschen in einer Transaktion zusammen, die erst nach dem Abarbeiten der Form_Error-Prozedur aufgelöst wird. Wie also können wir hier die Aktualisierung durchführen, wenn wir diese nicht direkt nach dem Bearbeiten der Daten auslösen können? Ich habe es auf verschiedene Arten probiert – und zwar mit Prozeduren, die durch Ereignisse wie Beim Anzeigen, Beim Löschen, Vor Löschbestätigung oder Nach Löschbestätigung ausgelöst wurden. Der Haken: All die Löschen-Ereignisse feuern nicht, weil wir ja keinen Datensatz über das Formular löschen, sondern dies über die Execute-Methode des Database-Objekts erledigen. Und Beim Anzeigen wird nicht ausgelöst, weil wir ja nicht den Datensatz wechseln – dieser wird zwar als gelöscht markiert, aber der Datensatzzeiger wird nicht auf einen anderen Datensatz verschoben. Es gibt aber noch eine Variante: Wenn der Benutzer den Datensatz samt der verknüpften Datensätze löschen will, löschen wir zuerst die verknüpften Datensätze über die DELETE-Anweisung mit der Execute-Methode und den Datensatz mit dem entsprechenden Befehl zur Steuerung der Benutzeroberfläche. Das wäre dann RunCommand acCmdDeleteRecord:

Es gibt ein Problem mit der Transaktion beim Löschen.

Bild 11: Es gibt ein Problem mit der Transaktion beim Löschen.

Private Sub Form_Error(...)
     ...
     Select Case DataErr
         Case 3200
             ...
             db.Execute "DELETE FROM tblBestellungen " _
                 "WHERE KundeID = " & lngKundeID, dbFailOnError
                 RunCommand acCmdDeleteRecord
             End If
             Response = acDataErrContinue
             Me.Requery
     End Select
End Sub

Hier funktioniert alles wie gewünscht. Allerdings erscheinen dann leider noch weitere Meldungen, die durch RunCommand acCmdDeleteRecord hervorgerufen werden, die wir aber temporär deaktivieren können (siehe Bild 12). Dazu schließen wir diese Anweisung jeweils in die DoCmd.SetWarnings-Anweisungen mit den jeweils erforderlichen Parametern ein:

Meldung beim Löschen eines Datensatzes

Bild 12: Meldung beim Löschen eines Datensatzes

DoCmd.SetWarnings False
RunCommand acCmdDeleteRecord
DoCmd.SetWarnings True

Auf diese Weise unterbinden wir Anzeige der Meldungen effizient.

Zusammenfassung und Ausblick

Dieser Beitrag zeigt, welche Einstellung für das Verhalten beim Löschen verknüpfter Datensätze relevant sind. Außerdem erhalten Sie Hinweise auf die Möglichkeiten, die vom System gelieferten Meldungen beim Versuch, verknüpfte Daten zu löschen, durch eigene Meldungen zu ersetzen. Schließlich lernen Sie, wie Sie verknüpfte Daten, die eigentlich nicht gelöscht werden können, nach Rückfrage beim Benutzer dennoch löschen.

Download

Download

Die .zip-Datei enthält folgende Dateien:

LoeschenVonInBeziehungStehendenDaten.accdb

Beispieldateien downloaden

© 2003-2018 André Minhorst Alle Rechte vorbehalten.