Benutzer mit den meisten Antworten
Aktualisierung in verknüpfter Tabelle schlägt fehl - Access 2010, SQL Server, ODBC

Frage
-
Hallo zusammen,
in einer Access-Anwendung, die auf per ODBC eingebundene SQL Server-Tabellen und -Views zugreift, habe ich unter bestimmten Konstellationen Probleme mit der Datensatzaktualisierung. Es gibt eine Reihe Listenformularen, deren Daten per Abfrage generiert werden und innerhalb der Listen nicht aktualisiert werden sollen. Per Doppelklick auf eine ID wird der eigentliche Datensatz geöffnet. Das Problem ist, dass ich den Datensatz nicht aktualisieren kann, wenn eine der Listen geöffnet ist, weil der Vorgang dann in einen Timeout läuft. Ich habe das nun so geregelt, dass vor dem Laden des Formulars die Listenformulare geschlossen werden. Danach kann ich den Datensatz des Pflegeformulars auch problemlos aktualisieren.
Es ist übrigens unerheblich, welche Technik ich anwende, um den Datensatz zu aktualisieren. Aus dem Pflegeformular heraus wird der Datensatz per Stored Procedure aktualisiert. Bei geöffneter Liste funktioniert das so wenig wie die Verwendung von Aktualisierungsabfragen, Updates auf Recordets oder Pass-Through-Abfragen. Beim Öffnen des Pflegeformulars wird eine Abfrage geöffnet, deren Daten in ein Objekt geschrieben werden. Die Abfrage gibt daher auch nur ein ReadOnly-Recordset zurück, das unmittelbar darauf verworfen wird. Alle Datenänderungen werden zunächst am Objekt vorgenommen und dann per SP in die Datenbank zurückgeschrieben.
Beim Aufruf eines Datensatzes muss der aktuelle Benutzer in ein Feld der Tabelle geschrieben werden. Steht in dem Feld etwas drin, kann der Datensatz von keinem anderen Benutzer geöffnet werden und es wird eine Meldung ausgegeben, welcher Benutzer den Datensatz in Bearbeitung hat. Diese Aktualisierungsabfrage wird beim Aktivieren des Formulars ausgeführt, nachdem die aufrufende Liste bereits geschlossen ist. Sie läuft trotzdem in einen Timeout. Beim Schließen des Pflegeformulars wird ebenfalls eine Aktualisierungsabfrage gestartet, die das entsprechende Feld wieder löscht. Das funktioniert einwandfrei.
Dieses merkwürdige Verhalten kostet mich schon immens viel Zeit. Früher habe ich Access-Frontends als adp/ade entwickelt, wobei solche Szenarien absolut problemlos zu entwickeln waren. Habe ich einen Denkfehler im Zusammenhang mit den ODBC-verknüpften Tabellen?
Für jedwede Hilfe vielen Dank.
M. Schörner
- Bearbeitet M. Schörner Dienstag, 24. Oktober 2017 07:52
Antworten
-
Das Problem konnte ich folgendermaßen lösen:
Private Sub R_ID_DblClick(Cancel As Integer) retoureID = Me.R_ID AufrufendesFormular = "frmOffenePostenAlleMitarbeiter" Me.Recordset.Close Set Me.Recordset = Nothing DoCmd.Close Call prcOpenSpecialOP(retoureID) End Sub
Dadurch ist sichergestellt, dass das Recordset samt Zugriffshandle auf die SQl Server Tabelle beendet ist. Der darauf folgende Aufruf der Aktualisierungsabfrage funktioniert danach perfekt.
Jedem, der sich hier darüber Gedanken gemacht hat, danke ich.
Liebe Grüße,
Michael- Als Antwort markiert M. Schörner Dienstag, 24. Oktober 2017 13:12
Alle Antworten
-
Am 23.10.2017 schrieb M. Schörner:
in einer Access-Anwendung, die auf per ODBC eingebundene SQL Server-Tabellen und -Views zugreift, habe ich unter bestimmten Konstellationen Probleme mit der Datensatzaktualisierung. Es gibt eine Reihe Listenformularen, deren Daten per Abfrage generiert werden und innerhalb der Listen nicht aktualisiert werden sollen. Per Doppelklick auf eine ID wird der eigentliche Datensatz geöffnet. Das Problem ist, dass ich den Datensatz nicht aktualisieren kann, wenn eine der Listen geöffnet ist, weil der Vorgang dann in einen Timeout läuft. Ich habe das nun so geregelt, dass vor dem Laden des Formulars die Listenformulare geschlossen werden. Danach kann ich den Datensatz des Pflegeformulars auch problemlos aktualisieren.
Haben die Tabellen denn auch ein Timestamp Feld? Falls ja, hast Du das
in Access eingebunden? Welche exakte Fehlermeldung kommt?Es ist übrigens unerheblich, welche Technik ich anwende, um den Datensatz zu aktualisieren. Aus dem Pflegeformular heraus wird der Datensatz per Stored Procedure aktualisiert. Bei geöffneter Liste funktioniert das so wenig wie die Verwendung von AKtualisierungsabfragen, Updates auf Recordets oder Pass-Through-Abfragen. Beim Öffnen des Pflegeformulars wird eine Abfrage geöffnet, deren Daten in ein Objekt geschrieben werden. Die Abfrage gibt daher auch nur ein ReadOnly-Recordset zurück, das unmittelbar darauf verworfen wird. Alle Datenänderungen werden zunächst am Objekt vorgenommen und dann per SP in die Datenbank zurückgeschrieben.
Ohne eingebundene Tabellen zu arbeiten, wäre an dieser Stelle
vermutlich zielführender.
Bern Jungbluth hat dazu auf einer der letzten AEKs einen Vortrag
gehalten. Im Downloadbereich gibt es auch eine kleine Beispiel
Datenbank.Servus
Winfried
Access-FAQ: http://www.donkarl.com/AccessFAQ.htm Access-Stammtisch: http://www.access-muenchen.de
NNTP-Bridge für MS-Foren: http://communitybridge.codeplex.com/
vbeTwister: http://www.vbetwister.com/ -
Hallo Winfried,
dank für Deine Antwort.
Die Fehlermeldung ist
"Error 3157 (ODBC: Aktualisierung in einer verknüpften Tabelle 'dbo_tblRetouren' fehlgeschlagen.) in procedure LockUnlockRetoure of Klassenmodul clsRetoureDB"
Ein Timestamp-Feld ist in der zugrunde liegenden Retouren-Tabelle vorhanden. Das Feld ist in alle Abfragen etc. eingebunden. Die Aufrufreihenfolge ist folgende:
- Öffnen der Liste (die eigentliche Liste ist ein Unterformular des aufgerufenen Formulars).
- Doppelklick auf die ID des zu öffnenden Datensatzes ruft eine Sub auf, die überprüft, ob ein anderer Benutzer den Datensatz gerade bearbeitet, alle offenen Listenformulare schließt und dann das Pflegeformular öffnet.
- Im Form_Load-Ereignis des Pflegeformulars wird das dem Formular zugrunde liegende Objekt erzeugt und mit Daten gefüllt, die eine Access-Abfrage liefert.
- Im Form_Activate-Ereignis soll in die Tabelle der aktuelle Benutzer geschrieben werden; hier läuft die Aktion in den Timeout (es ist vollkommen gelichgültig, wo und wann ich diese Aktionsabfrage aufrufe; ich habe weitgehend alle sinnvollen Positionen ausprobiert).
- Im Form_Close-Ereignis wird die Sub erneut aufgerufen, um das Benutzerfeld in der Tabelle wieder zu leeren. Hier läuft die Aktionsabfrage nie in einen Timeout.
- Das Listenformular wird wieder angezeigt.
Selbst wenn ich den Aufruf des Pflegeformulars außen vor lasse, d.h. die Aktualisierung der Tabelle direkt nach dem Schließen der Liste vornehme, laufe ich in den Timeout. Kann es sein, dass zwar das Formular geschlossen ist bzw. nicht mehr angezeigt wird, das zugrunde liegende Recordset aber so lange existent bleibt, bis alle Funktionsaufrufe abgeschlossen sind?
Der Code sieht folgendermaßen aus (aufs Wesentliche gekürzt):
Private Sub R_ID_DblClick(Cancel As Integer) retoureID = Me.R_ID AufrufendesFormular = "frmOffenePostenAlleMitarbeiter" DoCmd.Close acForm, AufrufendesFormular Call prcOpenSpecialOP(retoureID) End Sub Sub prcOpenSpecialOP(ByVal pLfdNr As Long) If IsFormLoaded("frmMitarbeiterRetouren") = True Then DoCmd.Close acForm, "frmMitarbeiterRetouren" End If ... myRetMgr.RetoureLockUnlock pLfdNr, CurrentUser.Mitarbeiter End Sub Public Sub LockUnlockRetoure(ByVal Retoure As Long, ByVal CurrentUser As String) Dim db As Database Dim qdef As QueryDef Set db = CurrentDb If Len(CurrentUser) > 0 Then Set qdef = db.QueryDefs("qupdRetoureLock") qdef.Parameters("@retoure").Value = Retoure qdef.Parameters("@currentUser").Value = CurrentUser qdef.Execute dbSeeChanges Else Set qdef = db.QueryDefs("qupdRetoureUnlock") qdef.Parameters("@retoure").Value = Retoure qdef.Execute dbSeeChanges End If Set qdef = Nothing Set db = Nothing End Sub
Viele Grüße,
Michael -
Das Problem konnte ich folgendermaßen lösen:
Private Sub R_ID_DblClick(Cancel As Integer) retoureID = Me.R_ID AufrufendesFormular = "frmOffenePostenAlleMitarbeiter" Me.Recordset.Close Set Me.Recordset = Nothing DoCmd.Close Call prcOpenSpecialOP(retoureID) End Sub
Dadurch ist sichergestellt, dass das Recordset samt Zugriffshandle auf die SQl Server Tabelle beendet ist. Der darauf folgende Aufruf der Aktualisierungsabfrage funktioniert danach perfekt.
Jedem, der sich hier darüber Gedanken gemacht hat, danke ich.
Liebe Grüße,
Michael- Als Antwort markiert M. Schörner Dienstag, 24. Oktober 2017 13:12
-
Hallo,M. Schörner wrote:> in einer Access-Anwendung, die auf per ODBC eingebundene SQL> Server-Tabellen und -Views zugreift, habe ich unter bestimmten> Konstellationen Probleme mit der Datensatzaktualisierung. Es gibt eine> Reihe Listenformularen, deren Daten per Abfrage generiert werden und> innerhalb der Listen nicht aktualisiert werden sollen. Per Doppelklick> auf eine ID wird der eigentliche Datensatz geöffnet. Das Problem ist,> dass ich den Datensatz nicht aktualisieren kann, wenn eine der Listen> geöffnet ist, weil der Vorgang dann in einen Timeout läuft. Ich habe das> nun so geregelt, dass vor dem Laden des Formulars die Listenformulare> geschlossen werden. Danach kann ich den Datensatz des Pflegeformulars> auch problemlos aktualisieren.Liegt vermutlich daran, dass die Listen relativ lang sind und vom Servernicht in einem Zug geladen werden. Anders als Access als Backend erwartetder Server, dass die angeforderten Daten vom Client auch wirklich abgeholtwerden, und nicht, wie in Access praktiziert, im Hintergrund nachgeladenwerden, während der Benutzer schon mit dem arbeiten kann, was er sieht. ImActivity Monitor auf dem Server sieht man dann das berühmteAsync_Network_IO und nachfolgende Prozesse müssen warten -> Timeout.Umgehen lässt sich das Problem, indem man nach dem Öffnen direkt einenMoveLast macht, was Access zwingt, das angeforderte Recordset komplett zuladen, damit der Server wieder frei für andere Anfragen ist.Also, im gebundenen Formular:Private Sub Form_Open(Cancel As Integer)Me.Painting = FalseWith Me.Recordset.MoveLast.MoveFirstEnd WithMe.Painting = TrueEnd SubSollten im geöffneten Formular Requeries gemacht werden, gilt das gleiche.Wenn ein bestimmter Datensatz angesprungen werden soll, siehe> Es ist übrigens unerheblich, welche Technik ich anwende, um den> Datensatz zu aktualisieren. Aus dem Pflegeformular heraus wird der> Datensatz per Stored Procedure aktualisiert.Es ist meistens problematisch, mit unterschiedlichen Methoden (gebundenesFormular, SQL, PT) auf dieselben Daten zugreifen zu wollen. Keine derMethoden ist besser oder schlechter, je nach Anwendung sind manchmalgebundene Formulare besser (Komfort beim Datenzugriff), manchmal SQL bzw.PassThrough (Performance).Der Rest der Probleme sieht nach Folgefehlern aus.Gruss - Peter--Mitglied im http://www.dbdev.org