none
Schreibkonflikt bei ODBC Zugriff auf SQL-Server

    Frage

  • Hallo,

    ich habe ein Formular, das über eine eingebundene Tabelle (ODBC) auf den SQL-Server zugreift. Wenn per Code Daten in der Tabelle geändert wurden und anschließend Daten im Formular geändert werden sollen, kommt die Meldung "Ein anderer Benutzer hat diesen Datensatz bearbeitet...". Um das zu verhindern, mache ich nach den Änderungen im Code ein MeinFormular.Refresh. Das funktioniert allerdings nicht, wenn die Daten sortiert sind (OrderBy) und ich im 1. Datensatz bin. Was mache ich falsch?

    Die Tabelle hat einen TIMESTAMP, einen UNIQUEIDENTIFIER und einen PRIMARY KEY:

    CREATE TABLE     tblTest  ( tstTS TIMESTAMP, tstGUID UNIQUEIDENTIFIER, tstID INT IDENTITY PRIMARY KEY, tstMatchcode VARCHAR(3) )

    Wenn ich das ODBC-Aktualisierungsinterval auf 1s setze, funktioniert es zwar, aber das ist wohl nicht Sinn der Sache?

    Thomas

    Montag, 25. Juni 2012 10:37

Antworten

  • Hallo Thomas

    Ja, die Methoden Refresh und Requery sind eigentlich genau das, was der Name sagt. Der Unterschied liegt darin, dass ein Refresh (wie auch der ODBC Refresh nach Ablauf des ODBC Refresh Intervals) die existierenden Daten aktualisiert, also den Inhalt der bereits eingelesenen Datensätze aktualsiert. Der Requery liest die Datenquelle komplett neu ein, indem er die Query ausführt. Daher werden beim Requery die gelöschten Datensätze entfernt und die neuen angezeigt. Beim Refresh werden die gelöschten als "gelsöcht" gekennzeichnet und neue werden nicht angezeigt. Das ist eigentlich der Hauptunterschied.

    Zu den Konkurrenzupdates: Ich denke, es ist richtig, wenn eine Meldung kommt, wenn der Datensatz zwischenzeitlich an einem anderen Arbeitsplatz geändert wurde. Es stimmt ja dann auch. Was sollte Access sonst machen?

    Zum Refresh Intervall: Ich selber lasse diese Einstellungen immer so, wie diese Standard eingestellt sind. Ich habe festgestellt, dass es sich nicht lohnt, hier etwas zu verändern. Das heisst, das Refresh interval ist bei mir auf 1500 Sekunden (25 Minuten) gesetzt und damit bin ich bisher gut gefahren. Es lohnt sich nicht, dieses zu verkürzen, weil dann sonst die Benutzer teilweise wieder mit den aktualisierten Daten beworfen werden. Im Gegenteil: könntest diesem Refresh auch komplett ausschalten (auf 0 setzen), weil es eigentlich im interaktiven Betrieb kaum Sinn macht, dass die Daten von Zeit zu Zeit neu eingelesen werden.

    Wichtiger ist, dass Du das Default record locking auf "No locks" setzt. Im ODBC Multiuser Umfeld macht es kaum Sinn Datensätze während längerer Zeit zu sperren. Solche Locks können andere Benutzer aussperren. Access checkt beim Update immer über die Timestamp Spalte (falls vorhanden, sont über einen Vergleich aller Spalten), ob der Datensatz zwischenzeitlich geändert worden ist. Das ist eigentlich das richtige Vorgehen, um Concurrency Situationen geregelt zu handhaben.

    Übrigens: Ein gutes Datenbank und Anwendungsdesign, sowie eine vernünftige Organisation hilft meist solche  Konkurrenz-Updates auszuschliessen. Wenn mehrere Benutzer den Bedarf haben, am gleichen Datensatz zu arbeiten, dann ist evt. auch die Aufgaben Verteilung und die Organisation nicht ganz optimal oder der Datensatz sollte in zwei Teile geteilt werden (1:1 Beziehung), abhängig von den Aufgaben, die durchgeführt werden müssen, um nicht den gleichen Datensatz von mehreren Seiten ändern zu müssen.

    Gruss

    Henry

    • Als Antwort markiert Thomas Warnke Dienstag, 26. Juni 2012 08:24
    Dienstag, 26. Juni 2012 07:59

Alle Antworten

  • Hallo Thomas

    Thomas Warnke wrote:

    ich habe ein Formular, das über eine eingebundene Tabelle (ODBC) auf den
    SQL-Server zugreift. Wenn per Code Daten in der Tabelle geändert wurden
    und anschließend Daten im Formular geändert werden sollen, kommt die
    Meldung "Ein anderer Benutzer hat diesen Datensatz bearbeitet...". Um das
    zu verhindern, mache ich nach den Änderungen im Code ein
    MeinFormular.Refresh. Das funktioniert allerdings nicht, wenn die Daten
    sortiert sind (OrderBy) und ich im 1. Datensatz bin. Was mache ich
    falsch?

    Verwende MeinFormular.Requery anstelle von MeinFormular.Refresh. Falls es ein Endlosformular ist, vorher den Bookmark merken und anschliessend diesen wieder anspringen.

    Besser wäre es allerdings, per Code nicht Daten in der Tabelle zu ändern, sondern diese Änderungen dem Formular zu überlassen und die geänderten Datenfelder in das Formular zu schreiben. Wenn es unbedingt nötig ist, vorgängig kontrollieren, ob das Formular Dirty ist und dann die dort bereits gemachten Anpassungen nach Rückfrage entweder rückgängig machen oder vorgängig in die DB schreiben, bevor der Code auf die Tabelle zugreift.

    Gruss
    Henry

    Dienstag, 26. Juni 2012 04:13
  • Hallo Henry,

    Verwende MeinFormular.Requery anstelle von MeinFormular.Refresh. Falls es ein Endlosformular ist, vorher den Bookmark merken und anschliessend diesen wieder anspringen.

    Besser wäre es allerdings, per Code nicht Daten in der Tabelle zu ändern, sondern diese Änderungen dem Formular zu überlassen und die geänderten Datenfelder in das Formular zu schreiben. Wenn es unbedingt nötig ist, vorgängig kontrollieren, ob das Formular Dirty ist und dann die dort bereits gemachten Anpassungen nach Rückfrage entweder rückgängig machen oder vorgängig in die DB schreiben, bevor der Code auf die Tabelle zugreift.

    danke für die Antwort. Requery funktioniert natürlich, wobei ich bisher dachte, dass Refresh nur den aktuellen Datensatz neu holt. Hab aber gerade im Profiler gesehen, dass auch Refresh alle Datensätze neu lädt.

    Von daher wäre es wirklich besser, die geänderten Daten in das Formular zu schreiben und zu speichern. Falls der Datensatz zwischenzeitlich an einem anderen Arbeitsplatz geändert wurde, kommt dabei allerdings ein Fehler.

    Auf welchen Wert sollte man das ODBC-Aktualisierungsinterval stellen?

    Gruß Thomas

    Dienstag, 26. Juni 2012 07:29
  • Hallo Thomas

    Ja, die Methoden Refresh und Requery sind eigentlich genau das, was der Name sagt. Der Unterschied liegt darin, dass ein Refresh (wie auch der ODBC Refresh nach Ablauf des ODBC Refresh Intervals) die existierenden Daten aktualisiert, also den Inhalt der bereits eingelesenen Datensätze aktualsiert. Der Requery liest die Datenquelle komplett neu ein, indem er die Query ausführt. Daher werden beim Requery die gelöschten Datensätze entfernt und die neuen angezeigt. Beim Refresh werden die gelöschten als "gelsöcht" gekennzeichnet und neue werden nicht angezeigt. Das ist eigentlich der Hauptunterschied.

    Zu den Konkurrenzupdates: Ich denke, es ist richtig, wenn eine Meldung kommt, wenn der Datensatz zwischenzeitlich an einem anderen Arbeitsplatz geändert wurde. Es stimmt ja dann auch. Was sollte Access sonst machen?

    Zum Refresh Intervall: Ich selber lasse diese Einstellungen immer so, wie diese Standard eingestellt sind. Ich habe festgestellt, dass es sich nicht lohnt, hier etwas zu verändern. Das heisst, das Refresh interval ist bei mir auf 1500 Sekunden (25 Minuten) gesetzt und damit bin ich bisher gut gefahren. Es lohnt sich nicht, dieses zu verkürzen, weil dann sonst die Benutzer teilweise wieder mit den aktualisierten Daten beworfen werden. Im Gegenteil: könntest diesem Refresh auch komplett ausschalten (auf 0 setzen), weil es eigentlich im interaktiven Betrieb kaum Sinn macht, dass die Daten von Zeit zu Zeit neu eingelesen werden.

    Wichtiger ist, dass Du das Default record locking auf "No locks" setzt. Im ODBC Multiuser Umfeld macht es kaum Sinn Datensätze während längerer Zeit zu sperren. Solche Locks können andere Benutzer aussperren. Access checkt beim Update immer über die Timestamp Spalte (falls vorhanden, sont über einen Vergleich aller Spalten), ob der Datensatz zwischenzeitlich geändert worden ist. Das ist eigentlich das richtige Vorgehen, um Concurrency Situationen geregelt zu handhaben.

    Übrigens: Ein gutes Datenbank und Anwendungsdesign, sowie eine vernünftige Organisation hilft meist solche  Konkurrenz-Updates auszuschliessen. Wenn mehrere Benutzer den Bedarf haben, am gleichen Datensatz zu arbeiten, dann ist evt. auch die Aufgaben Verteilung und die Organisation nicht ganz optimal oder der Datensatz sollte in zwei Teile geteilt werden (1:1 Beziehung), abhängig von den Aufgaben, die durchgeführt werden müssen, um nicht den gleichen Datensatz von mehreren Seiten ändern zu müssen.

    Gruss

    Henry

    • Als Antwort markiert Thomas Warnke Dienstag, 26. Juni 2012 08:24
    Dienstag, 26. Juni 2012 07:59
  • Danke, das war sehr interessant. In größeren Umgebungen wird es aber auch bei guter Organisation hin und wieder zu Konkurrenzupdates kommen.

    Merkwürdig bleibt trotzdem, dass Refresh im 1. Datensatz fehlschlägt..

    Gruß Thomas

    Dienstag, 26. Juni 2012 08:24
  • Ich hab ein ähnliches Problem aber mit anderer Vorgeschichte:

    Ich hab ein Unterformular in dem ein User einen neuen Datensatz anlegen kann, z.B. einen neuen Termin erfasst. Wenn er jetzt unterbrochen wird, d.h. den Datensatz nicht verläßt und damit auch nicht speichert,dann passiert es immer wieder mal daß der Schreibkonflikt kommt und der Datensatz als "GELÖSCHT" dargestellt wird. In die Zwischenablage kopieren und auf neuem Datensatz einfügen funktioniert meist.

    Konkrete Ursache konnte ich noch nicht feststellen, im Moment sieht es so aus, als ob ein anderer User in der Zwischenzeit auch einen Datensatz angelegt hat, in der Tabelle fehlt soweit ich das sehe auch eine ID.

    Server = MS-SQL 2008, Client = MS Access 2010/32, Einbindung ist ODBC

    Timestamp+GUID sind vorhanden

    Irgendwie komm ich hier nicht mehr weiter...

    lg,Christian

    Donnerstag, 25. Oktober 2012 14:52