none
Probelm mit SqlDataAdapter RRS feed

  • Frage

  • Hallo, ich habe folgendes Problem mit meinem in VB2008 geschriebenen Programm: Daten aus einer DB werden ausgelesen und in eine Datatable gespeichert:

    M_SQLStr = "SELECT * " & _

    "FROM S_PARAM_PRM " & _

    "WHERE PRM_TYP = 'PLNA'  "

    P_DA_PLANER = New SqlDataAdapter()

    P_DA_PLANER.SelectCommand = New SqlCommand(M_SQLStr, M_ConnSql)

    P_CB_PLANER = New SqlCommandBuilder(P_DA_PLANER)

    P_DA_PLANER.Fill(P_DTA_Planer)

    M_DVWochPlnDB = New DataView(P_DTA_Planer)

    Zur laufzeit können die User die Daten in der Tabelle ändern:

    M_DVWochPlnDB(0).Item("PRM_String") = „test“

    M_DVWochPlnDB(0).EndEdit()

    oder auch neue Zeilen anlegen:

    Dim RowNeu As DataRowView

    RowNeu = M_DVWochPlnDB.AddNew()

    RowNeu("PRM_Zahl") = M_KalendWocheID

    RowNeu.EndEdit()

    Die Änderungen werden dann in der Datenbank gespeichert:

    P_DA_PLANER.Update(P_DTA_Planer)

    Die neu angelegten Zeilen und die Änderungen der aus der Datbenbank geladenen Zeilen werden immer korrekt in der Datenbank gespeichert. Wenn ich aber eine neue Zeile anlege, sie in der Datenbak speichere und sie später in gleicher Situzung ändere, dann bekommen ich beim Versuch die Änderung zu speichern eine Fehlermeldung:

    Parallelitätsverletzung: Der UpdateCommand hat sich auf 0 der erwarteten 1 Datensätze ausgewirkt“. Ich habe schon rausbekommen, dass es danran liegt, dass in der Datatable nach der ersten Speicherung der  Primärschlüssel fehlt.

    Hat vielleicht jemand eine Lösung für dieses Problem?

    Gruß

    Christoph

    Montag, 7. Januar 2013 14:24

Antworten

  • Hi Christoph,
    Du musst Dir Gedanken über die von Dir genutzte Technologie machen.
     
    Wenn Du einen neuen Datensatz in Deinem Programm anlegst, dann bekommt der Datensatz den Rowstate “added” und in der Autowert-Spalte wird ein Wert eingetragen (z.B. –1). Wenn dann das Update ausgeführt wird, wird an Hand des Rowstates diese neue Datensatz mit einem INSERT der externen Datenbank hinzugefügt. Dabei wird in der Autowert-Spalte von der Datenbank ein unikater neuer Wert eingetragen (z.B. höchster bisher vergebener Wert +1). Dieser Wert weicht im typischen Fall von den im Anwendungsprogramm vorhandenen Wert ab. Dein Datensatz bekommt (wegen dem implizit ausgeführten AcceptChanges) den neuen Zustand “unchanged”.
     
    Wenn Du jetzt dieses ehemals neu erfassten Datensatz veränderst, wird der Rowstate in “modified” geändert. Beim nachfolgenden Update wird an Hand des Wertes der Primärschlüsselspalte dieser Datensatz in der Datenbank identifiziert und mit einem UPDATE-Sql geändert. Wenn jetzt wie üblich die Autowert-Spalte als Primärschlüsselspalte genutzt wird, dann wird der in der externen Datenbank zu ändernde Datensatz nicht gefunden. Das Ergebnis ist “0 Änderungen”, was dem Programm als Konkurrenzfehler mitgeteilt wird.
     
    Lösen kann man das Problem, indem nach dem Speichern neuer Datensätze, mindestens die neu vergebenen Autowerte zurückgelesen werden und in die betroffenen Datensätze eingetragen werden. Das kann man im OnRowUpdated- Ereignis des DataAdapters machen oder bei Datenbankservern, die mehrfache SQL-Anweisungen unterstützen, mit einer angehängten SELECT-Anweisung.
     
    Diese Arbeitsweise ist unbedingt notwendig, wenn verknüpfte Daten (Master-Child) genutzt werden, oder, wenn der Datenbankserver über Trigger noch weitere Feldinhalte ändert. Dann sollte der gesamte neu hinzugefügte oder auch geänderte Datensatz am Ende des Updates zurückgelesen werden.
     
    --
    Peter Fleischer
    Dienstag, 8. Januar 2013 08:41

Alle Antworten

  • Hallo Christoph,

    ich gehe mal davon aus, dass dein Primärschlüssel ein IDENTITY Wert ist? Falls ja, schau mal hier:

      http://msdn.microsoft.com/de-de/library/system.data.common.dataadapter.acceptchangesduringupdate.aspx

    und hier:

      http://msdn.microsoft.com/de-de/library/ks9f57t0.aspx

    Da solltest Du sehen können, wie Du das machen musst.


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community

    Montag, 7. Januar 2013 14:36
    Moderator
  • Hallo Stephan,

    vielen Dank für Deine Anwtort. Ich habe gleich Deinen Tipp mit

    P_DA_PLANER.AcceptChangesDuringUpdate = False

    getestet und der Fehler tritt tatsächlich nicht mehr auf. Nun bekomme ich aber die gleiche Fehlermeldung, wenn ich Änderungen in einem bereits einmal gespeicheten Datensatz nochmal in der gleichen Sitztung speichern will!! Es scheint also doch kein Problem mit dem Primärschlüßel zu sein, oder? Ich bin verzweifelt!!!! -:)

    Gruß

    Christoph


    Dienstag, 8. Januar 2013 07:44
  • Hi Christoph,
    Du musst Dir Gedanken über die von Dir genutzte Technologie machen.
     
    Wenn Du einen neuen Datensatz in Deinem Programm anlegst, dann bekommt der Datensatz den Rowstate “added” und in der Autowert-Spalte wird ein Wert eingetragen (z.B. –1). Wenn dann das Update ausgeführt wird, wird an Hand des Rowstates diese neue Datensatz mit einem INSERT der externen Datenbank hinzugefügt. Dabei wird in der Autowert-Spalte von der Datenbank ein unikater neuer Wert eingetragen (z.B. höchster bisher vergebener Wert +1). Dieser Wert weicht im typischen Fall von den im Anwendungsprogramm vorhandenen Wert ab. Dein Datensatz bekommt (wegen dem implizit ausgeführten AcceptChanges) den neuen Zustand “unchanged”.
     
    Wenn Du jetzt dieses ehemals neu erfassten Datensatz veränderst, wird der Rowstate in “modified” geändert. Beim nachfolgenden Update wird an Hand des Wertes der Primärschlüsselspalte dieser Datensatz in der Datenbank identifiziert und mit einem UPDATE-Sql geändert. Wenn jetzt wie üblich die Autowert-Spalte als Primärschlüsselspalte genutzt wird, dann wird der in der externen Datenbank zu ändernde Datensatz nicht gefunden. Das Ergebnis ist “0 Änderungen”, was dem Programm als Konkurrenzfehler mitgeteilt wird.
     
    Lösen kann man das Problem, indem nach dem Speichern neuer Datensätze, mindestens die neu vergebenen Autowerte zurückgelesen werden und in die betroffenen Datensätze eingetragen werden. Das kann man im OnRowUpdated- Ereignis des DataAdapters machen oder bei Datenbankservern, die mehrfache SQL-Anweisungen unterstützen, mit einer angehängten SELECT-Anweisung.
     
    Diese Arbeitsweise ist unbedingt notwendig, wenn verknüpfte Daten (Master-Child) genutzt werden, oder, wenn der Datenbankserver über Trigger noch weitere Feldinhalte ändert. Dann sollte der gesamte neu hinzugefügte oder auch geänderte Datensatz am Ende des Updates zurückgelesen werden.
     
    --
    Peter Fleischer
    Dienstag, 8. Januar 2013 08:41
  • Hallo Peter

    danke für die ausführliche Erklärung, nun habe auch ich das Problem verstanden -:) Jetzt funktioniert alles einwandfrei!  Ich bin fälschlicherweise davon ausgegangen, dass ein DataAdapter komplett den Datenaustausch zwischen einer DataTable und der Datenbank und umgekehrt steuert. Wieso man dann doch selbst den neunen Primäschlüssel aus der DB auslesen und in die DataTable schrieben muss, ist mit nicht ganz klar. Das hätte der DataAdapter eigentlich auch machen müssen?!

    Gruß

    Mittwoch, 9. Januar 2013 06:19
  • Hi Christoph,
    das Rücklesen der im Datenbankserver geänderten Werte (Autowert und ggf. weitere Felder nach Trigger-Operation) funktioniert beim SQL-Server problemlos ohne weiteren Code, wenn eine SELECT-Anweisung angehängt wird. Wenn Du den Designer nutzt, brauchst Du dazu nur das entsprechende Häkchen setzen und brauchst keinen weiteren Code.
     
    --
    Peter Fleischer
    Mittwoch, 9. Januar 2013 07:31