Parallelitätsverletzung nach neuanlegen -> speichern -> ändern

  • VB.NET
  • .NET (FX) 4.5–4.8

Es gibt 8 Antworten in diesem Thema. Der letzte Beitrag () ist von Schoofi.

    Parallelitätsverletzung nach neuanlegen -> speichern -> ändern

    Ich habe beim Neuanlegen und nachträglichem Ändern desselben Datensatzes das Problem, das er mir eine Parallelitätsverletzung bringt.
    Wenn ich den Datensatz anlege funktioniert noch alles.
    Dann speichere ich ihn, da ist auch noch alles OK.
    Wenn ich diesen Datensatz anschließend noch mal ändere, tritt beim Speichern die Parallelitätsverletzung auf.
    Starte ich das Programm neu, kann ich auch den Datensatz ändern.
    Ich habe das in einem kleinen Formular mal nachgestellt.

    dsrechnerliste_be.updateall löst ein Adaptermanager.UpdateAll aus

    Quellcode

    1. Public Class frmTest
    2. Dim dtrowNutzer As dsRechnerliste_be.tbl_NutzerRow
    3. Public Sub New()
    4. ' Dieser Aufruf ist für den Designer erforderlich.
    5. InitializeComponent()
    6. DsRechnerliste_be = dsRechnerliste_be.GetInstance
    7. Me.bsNutzer.DataSource = DsRechnerliste_be
    8. ' Fügen Sie Initialisierungen nach dem InitializeComponent()-Aufruf hinzu.
    9. End Sub
    10. Private Sub btnNeu_Click(sender As Object, e As EventArgs) Handles btnNeu.Click
    11. dtrowNutzer = DirectCast(DsRechnerliste_be.tbl_Nutzer.NewRow, dsRechnerliste_be.tbl_NutzerRow)
    12. DsRechnerliste_be.tbl_Nutzer.Rows.Add(dtrowNutzer)
    13. Me.bsNutzer.Position = Me.bsNutzer.Find(DsRechnerliste_be.tbl_Nutzer.ID_NutzerColumn.ColumnName, dtrowNutzer.ID_Nutzer)
    14. End Sub
    15. Private Sub btnSpeichern_Click(sender As Object, e As EventArgs) Handles btnSpeichern.Click
    16. Me.bsNutzer.EndEdit()
    17. DsRechnerliste_be.Updateall()
    18. End Sub
    19. Private Sub btnLöschen_Click(sender As Object, e As EventArgs) Handles btnLöschen.Click
    20. Me.bsNutzer.RemoveCurrent()
    21. DsRechnerliste_be.Updateall()
    22. End Sub
    23. End Class


    Was muß ich anders machen, das das nicht mehr passiert ?
    jo - issn typischer Fall.
    Die Datenbank legt für zugefügte Datensätze (Insert) eigene PrimKeys an.
    Wenn du also vom Dataset aus updatest, ignoriert die Db den Dataset-Primkey und nimmt ihren eigenen.
    Der Datensatz hat also nun einen falschen Primkey, und wenn du den Datensatz updatest (Update), dann kann die DB den Dataset-PrimKey keinem Zuordnen und bätsch.

    Die Lösung ist aufwändig: Du musst nach jedem Insert die Db abfragen, welchen PrimKey sie vergeben hat, und den im Dataset einpflegen.

    In Dataset->Db gelöst.
    ich dachte eigentlich das ich damit gelöst habe.

    Quellcode

    1. Partial Class tbl_NutzerTableAdapter
    2. Private _IdentityCommand As New OleDbCommand("SELECT @@IDENTITY")
    3. Private Sub _RowUpdated(ByVal sender As Object, ByVal e As OleDbRowUpdatedEventArgs) Handles _adapter.RowUpdated
    4. If e.StatementType = StatementType.Insert Then
    5. _IdentityCommand.Connection = e.Command.Connection
    6. _IdentityCommand.Transaction = e.Command.Transaction
    7. e.Row(e.Row.Table.PrimaryKey(0)) = CInt(_IdentityCommand.ExecuteScalar())
    8. End If
    9. End Sub
    10. End Class

    Mit dem Code habe ich zumindest den aktuelle Primkey im datarow.
    Aber das war wohl demzufolge ein Trugschluß, der in diesem speziellen Fall nicht greift.
    Ich habe es gerade noch mal versucht einzugrenzen. Das Ansprechen ausschließlich über Datarow funktioniert (siehe Codebeispiel). Der Fehler muß also beim Umgang mit der Bindungsource liegen.

    Quellcode

    1. Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    2. Dim dtrowNutzer1 As dsRechnerliste_be.tbl_NutzerRow
    3. dtrowNutzer1 = DirectCast(DsRechnerliste_be.tbl_Nutzer.NewRow, dsRechnerliste_be.tbl_NutzerRow)
    4. With dtrowNutzer1
    5. .BKUAnmeldename = "GustavGans"
    6. DsRechnerliste_be.Updateall()
    7. DsRechnerliste_be.tbl_Nutzer.Rows.Add(dtrowNutzer1)
    8. .Nachname = "Gans"
    9. .Vorname = "Gustav"
    10. DsRechnerliste_be.Updateall()
    11. End With
    12. End Sub
    das ist ja auch ein komischer Code: Erst updateste alle, dann fügste eine Zeile zu und updatest nochmal alle.
    Probierma das erste UpdateAll wegzulassen.

    Was mich auch wundert: Was ist DsRechnerliste_be fürn Datentyp? Scheint ein Dataset, hat aber eine UpdateAll-Methode - die du vermutlich selbst drangebastelt hast, oder?
    Der Code diente nur der Fehlereingrenzung und der Simulation eines Nutzerverhaltens.
    Der Nutzer legt einen Datensatz an, speichert diesen und merkt dann das er noch was vergessen hat, bessert das ein und speichert nochmal.
    In dem simulierten Codebeispiel ohne Einbeziehung der Bindungsource klappts auch.
    Mache ich dies im Formular mit Bindingsource gehts schief.

    Quellcode

    1. Public Sub Updateall()
    2. Me.Adaptermanager.UpdateAll(Me)
    3. End Sub
    Unter Einbeziehung der Bindungsource verstehe ich, das Änderungen im Formular vorgenommen werden.
    Die gleichen Änderungen, die ich in dem Testbeispiel mit den 2 updates gemacht habe, führe ich im Formular durch.
    Also Datensatz neu anlegen, Nachname, Vorname eintragen, speichern BKUAnmdeldename eintragen, speichern.
    Dabei tritt die Parallelitätsverletzung auf.
    Im Testbeispiel wo ich nur mit der Datarow gearbeitet habe, passierte das nicht.
    bsnutzer.endedit wird vorm updateall ausgeführt. (siehe Codebeispiel im ersten Beitrag)