Announcement

Collapse
No announcement yet.

"Concurrency violation" beim Speichern von Daten

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • "Concurrency violation" beim Speichern von Daten

    Ich habe ein Problem beim Speichern von Daten in einer Mehrschicht-Anwendung. Die Datenzugriffschicht liegt in einer DLL auf dem IIS und wird über .NET-Remoting angesprochen. Die DAtenzugriffschicht ist zustandslos. Für das eigentliche Speichern der Daten habe ich eine Komponente geschrieben, welche ADO.NET kapselt. Diese Komponente ist als Singleton implementiert. Die zu Speichernden Daten werden in DataSets übergeben. Das Speichern erfolgt über DataAdapter.

    Mit dieser Lösung kann ich den selben Datensatz nicht zweimal hintereinander speichern. Beim zweiten Speicherversuch bekomme ich grundsätzlich eine Concurrency Violation. Wenn ich in der Client-Applikation die Eingabemaske verlasse und den Datensatz neu einlese, kann ich Änderungen wieder einmalig abspeichern.

    Ich habe schon in einigen Foren nach Lösungsmöglichkeiten gesucht, bin aber bisher nicht fündig geworden.

    Hat irgendjemand schon einmal ein ähnliches Problem gehabt ???

    Gruß
    Klaus

  • #2
    Hallo,

    welche WHERE-Einschränkung nutzt die vom DataAdapter implizit beim Zurückschreiben in die Datenbank verwendete UPDATE-Anweisung (siehe DataAdapter-Eigenschaft <i>UpdateCommand</i>)? Immer dann, wenn beim UPDATE-Aufruf in der Datenbanktabelle kein Datensatz zur WHERE-Einschränkung passt, löst ADO.NET die Exception <i>DBConcurrencyException</i> aus. Als Gründe kommen nur 2 Fälle in Frage: <br>
    1. Der zu aktualisierende Datensatz wurde in der Zwischenzeit von einem anderen Benutzer gelöscht, oder <br>
    2. Zur WHERE-Einschränkung der UPDATE-Anweisung gibt es kein Gegenstück in der Tabelle.

    Wenn die UPDATE-Anweisung als WHERE-Einschränkung <b>zusätzlich</b> zum Primärschlüsselwert auch die alten Feldwerte aller Spalten der Tabelle vergleicht (optimistisches Sperrverfahren), muss das nach dem UPDATE über SELECT neu eingelesene DataSet zurück zum Client, damit dort für den 2. Update-Aufruf die "richtigen" Feldwerte als WHERE-Einschränkung genutzt werden können.
    &#10

    Comment


    • #3
      Hallo,

      die WHERE-Klausel enthält alle Feldnamen als Parameter. Ich lese die Daten nach dem Update jedoch nicht neu ein. Auf der Clientseite rufe ich lediglich AcceptChanges() auf dem DataSet auf.

      Ich habe die Serverseite mittlerweile detailliert debugged. Das übergebene DataSet enthält die korrekten Originalwerte, welche für das Update-Statement benötigt werden. Was mich wundert ist der Aufbau der Where-Bedingung. Sie sieht in etwa so aus:

      ... where ( (<Mein_PrimaryKey> = @p10) AND ((<b>@p11 = 1</b> AND MANDANT IS NULL) OR (MANDANT = @p12)) AND ...

      Ich frage mich, was "@p11 = 1" bedeutet. Dieses Konstrukt gilt für alle Felder der Tabelle.

      Gibt es eine Möglichkeit herauszufinden, welche Werte die Parameter beim Update haben

      Comment


      • #4
        Hallo,

        &gt;..welche Werte die Parameter beim Update haben ?

        im Fall des MS SQL Server würde ich hier den <i>Profiler</i> auf die Lauer legen, damit dieser alle beim SQL Server eintreffenen Aufrufe mitprotokolliert.

        &gt;Dieses Konstrukt gilt für alle Felder der Tabelle.

        Immer dann, wenn eine Spalte einer Tabelle den NULL-Zustand zulässt, muss bei der WHERE-Einschränkung dieser Zustand explizit über IS NULL geprüft werden. Normalerweise sieht das dann aber so aus:

        a) Beispieltabelle
        <pre>
        <b>CREATE</b> <b>TABLE</b> UpdDemo
        (
        recid <b>INTEGER</b> <b>NOT</b> <b>NULL</b> <b>IDENTITY</b> <b>PRIMARY</b> <b>KEY</b>,
        wert1 <b>INTEGER</b> <b>NOT</b> <b>NULL</b>,
        wert2 <b>INTEGER</b> <b>NULL</b>
        )
        <b>GO</b>
        </pre>
        b) Die vom SqlDataAdapter generierte Anweisung:
        <pre>
        <b>UPDATE</b> UpdDemo <b>SET</b>
        wert1 = @wert1, wert2 = @wert2
        <b>WHERE</b>
        (recid = @Original_recid) <b>AND</b>
        (wert1 = @Original_wert1) <b>AND</b>
        (wert2 = @Original_wert2 <b>OR</b> @Original_wert2 <b>IS</b> <b>NULL</b> <b>AND</b> wert2 <b>IS</b> <b>NULL</b>);
        <br>
        <b>SELECT</b> recid, wert1, wert2
        <b>FROM</b> UpdDemo
        <b>WHERE</b> (recid = @recid)
        </pre>
        Der SqlDataAdapter liest den Datensatz in der BATCH-Anweisung neu ein, damit auch die von eventuell wirksamen Triggern vorgenommenen Änderungen garantiert beim Client landen

        Comment


        • #5
          Mittlerweile habe ich herausgefunden, wo mein Problem liegt. Dein Hinweis mit den Originalwerten hat mich letztendlich auf die richtige Spur gebracht. Alle Tabellen in der Datenbank haben Spalten, welche das Erstell- bzw. Änderungsdatum aufnehmen. Das Änderungsdatum setzte ich auf der Serverseite, bevor ich den Datensatz speichere. Da ich die gespeicherten Daten nicht erneut lese, stimmt das Änderungsdatum auf dem Client nicht mehr mit dem Änderungsdatum in der Datenbank überein und somit kann der Datensatz nicht gespeichert werden

          Comment

          Working...
          X