XML in SQLite Update Problem

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

Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von Kim.

    XML in SQLite Update Problem

    Hallo Zusammen,

    ich versuche mich an einer Lösung Daten aus einer SQL Tabelle über XML in eine SQLite Tabelle zu schreiben.

    VB.NET-Quellcode

    1. Private Sub SQLIte_Update()
    2. Dim SQLconnect As New Data.SQLite.SQLiteConnection()
    3. Dim SQLimport As New SQLiteDataAdapter("Select * from dtItem", "DataSource='C:\VB.NET Projekte\Datenbank\KMADaten.db" & "'")
    4. Dim SQLcb As New Data.SQLite.SQLiteCommandBuilder()
    5. SQLcb.DataAdapter = SQLimport
    6. SQLconnect.ConnectionString = "Data Source=C:\VB.NET Projekte\Datenbank\KMADaten.db" & ";"
    7. Dim dt As dtsBuffer.ItemBufferDataTable = DtsBuffer1.ItemBuffer
    8. dt.Clear()
    9. dt.ReadXml("C:\VB.NET Projekte\dtNAVItem.xml")
    10. 'SQLimport.InsertCommand = SQLcb.GetUpdateCommand
    11. SQLimport.Update(dt)
    12. CSVBuffer.CSVBuffer_DataGridView.DataSource = dt
    13. CSVBuffer.CSVBuffer_DataGridView.Refresh()
    14. End Sub


    Klappt auch wenn es nur neue Daten sind.
    bei vorhandenen Daten auf Basis der Primärschlüsselspalte No_ bekomme ich folgende Exception.

    "System.Data.SQLite.SQLiteException: "constraint failed
    UNIQUE constraint failed No_"

    Kann mir hier vllt. wer weiterhelfen?

    Besten Dank im Voraus

    Gruß

    Kim
    Naja, offensichtlich gibt es Zeilen, die gleiche Werte in einer Unique-Spalte haben. Eine Unique-Spalte lebt aber davon, dass alle Zeilen unterschiedliche Werte haben. Sonst wären die Einträge ja nicht eindeutig/unique/einmalig.
    Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von „VaporiZed“, mal wieder aus Grammatikgründen.

    Aufgrund spontaner Selbsteintrübung sind all meine Glaskugeln beim Hersteller. Lasst mich daher bitte nicht den Spekulatiusbackmodus wechseln.
    musste mal recherchieren, ob SQLite-Sql einen Befehl InsertOrUpdate kennt.
    Andernfalls wirds aufwändiger, weil du musst alle bestehenden PrimKeys abfragen und in deim Dataset diejenigen identifizieren, die dort auch vorhanden sind. Deren RowState muss auf RowState.Modified gesetzt werden, damit der DataAdapter sein UpdateCommand verwendet statt des Inserts.
    Möglicherweise treten dann immer noch Probleme mit DbConcurrency auf - dann muss der CommandBuilder anders eingestellt werden, dass er das nicht überprüft.
    Jo, hübsch.
    Da müsste man nun das InsertCommand des DataAdapters umändern auf Replace.
    Ist ein bischen tricky, weil da hat ja auch der CommandBuilder seine Finger drin.
    In Dataset->Db im SampleProjekt inne SqlServerPersistance, da werden aus einem Commandbuilder die Commands rausgezogen, und dem DataAdapter übergeben - wobei das Insert modifiziert wird.
    Ganz ähnliches würde ich auch fürs hiesige Problem anstreben.
    Super Danke!
    zeigt ja irgendwie wird es funktionieren.
    ich hab zwar noch gar kein Plan wie ich das umsetzen muss, aber ich versuche mich da mal rein zu lesen.



    Also ich habe jetzt mal folgendes probiert,

    VB.NET-Quellcode

    1. For Each row As DataRow In dt.Rows
    2. Dim SQLCommand As New SQLite.SQLiteCommand("Replace INTO dtItem (" & dt.Columns(0).ColumnName.ToString & ",[" & dt.Columns(1).ColumnName.ToString & "])VALUES('" & row(0).ToString & "','" & row(1).ToString & "')", SQLconnect)
    3. 'MsgBox(row(1).ToString)
    4. SQLimport.InsertCommand = SQLCommand
    5. SQLimport.Update(dt)
    6. Next


    Es funtioniert auch nur scheint er immer nur die erste Zeile zu updaten.
    Er schreibt nur die erste Zeile in die Datenbank.

    sieht vllt wer das Problem hier?

    Beiträge zusammengefügt. ~Thunderbolt

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Thunderbolt“ ()

    Ich würde es für das Problem halten, dass du meine Empfehlung aus post#6 scheinbar garnet angeguckt hast. Oder vielleicht flüchtig hingeguckt, iwas nicht verstanden, und dann nicht weiter nachgefragt.
    So kommt man aber nicht weiter.

    Hier sowas hätte ich mir vorgestellt. Also aus deinem Code in post#1 und dieser Vorlage im Tutorial-Download:

    VB.NET-Quellcode

    1. Public Sub New(connectionString As String, dts As DataSet)
    2. MyBase.New(dts)
    3. Dim con = New SqlConnection(EnsureMARS(connectionString))
    4. Using con.EnterOpen
    5. For Each tb In _RankedTables
    6. 'pro DataTable einen Adapter konfigurieren, mit allen 4 Commands
    7. Dim adp = New SqlDataAdapter(String.Format("Select `{0}`.* from `{0}`", tb.TableName), con)
    8. Using builder = New SqlCommandBuilder(adp) With {.ConflictOption = ConflictOption.OverwriteChanges}
    9. With adp
    10. .UpdateCommand = builder.GetUpdateCommand.Clone
    11. .InsertCommand = builder.GetInsertCommand.Clone
    12. TryInitAutoIncrement(tb, .InsertCommand)
    13. .DeleteCommand = builder.GetDeleteCommand.Clone
    14. .TableMappings.Add(DbDataAdapter.DefaultSourceTableName, tb.TableName)
    15. End With
    16. End Using
    17. _Adapters.Add(tb, adp)
    18. Next
    19. End Using
    20. End Sub
    leitet sich dieses Ergebnis ab:

    VB.NET-Quellcode

    1. Private Sub SQLIte_Update()
    2. Dim dt = DtsBuffer1.ItemBuffer
    3. dt.Clear()
    4. dt.ReadXml("C:\VB.NET Projekte\dtNAVItem.xml")
    5. Using SQLimport As New SQLiteDataAdapter("Select * from dtItem", "DataSource='C:\VB.NET Projekte\Datenbank\KMADaten.db" & "'")
    6. SQLimport.SelectCommand.Connection.Open()
    7. Using SQLcb As New Data.SQLite.SQLiteCommandBuilder() With {.ConflictOption = ConflictOption.OverwriteChanges, .DataAdapter = SQLimport}
    8. With SQLimport
    9. '.UpdateCommand = SQLcb.GetUpdateCommand.Clone
    10. .InsertCommand = SQLcb.GetInsertCommand.Clone
    11. .InsertCommand.CommandText = .InsertCommand.CommandText.ToLower.Replace("insert", "Replace")
    12. 'TryInitAutoIncrement(tb, .InsertCommand)
    13. '.DeleteCommand = SQLcb.GetDeleteCommand.Clone
    14. .TableMappings.Add(DbDataAdapter.DefaultSourceTableName, dt.TableName)
    15. End With
    16. End Using
    17. SQLimport.Update(dt)
    18. End Using
    19. CSVBuffer.CSVBuffer_DataGridView.DataSource = dt
    20. End Sub

    Ist allerdings ungetestet, weil ich hab kein SQLite installiert.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Ich habe mir dein TUT leider noch nicht ganz genau anschauen können und hatte einfach kurz mal probiert aus dem anderen Link was zu testen.
    Danke erstmal für die Antwort das sieht natürlich top aus.

    Er gibt mir eine Fehlermeldung aus in Zeile4 .InsertCommand = SQLcb.GetInsertCommand.Clone

    Fehler BC30512 "Option Strict On" lässt keine impliziten Konvertierungen von "Object" in "SQLiteCommand" zu.


    VB.NET-Quellcode

    1. Using SQLcb As New Data.SQLite.SQLiteCommandBuilder() With {.ConflictOption = ConflictOption.OverwriteChanges, .DataAdapter = SQLimport}
    2. With SQLimport
    3. '.UpdateCommand = SQLcb.GetUpdateCommand.Clone
    4. .InsertCommand = SQLcb.GetInsertCommand.Clone
    5. .InsertCommand.CommandText = .InsertCommand.CommandText.ToLower.Replace("insert", "Replace")
    6. 'TryInitAutoIncrement(tb, .InsertCommand)
    7. '.DeleteCommand = SQLcb.GetDeleteCommand.Clone
    8. .TableMappings.Add(DbDataAdapter.DefaultSourceTableName, dt.TableName)
    9. End With


    Die Farbe „Rot“ ist der Moderation vorbehalten. Farbe entfernt. ~Thunderbolt

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „Thunderbolt“ ()

    oh - gut - du programmierst Option Strict On!
    wie gesagt: ich hab kein SQLite - ich kenne nur die Clone-Funktion der SqlServer-Commands. Aber da kann man dann vermutlich casten:

    VB.NET-Quellcode

    1. .InsertCommand = DirectCast(SQLcb.GetInsertCommand.Clone, SQLiteCommand)
    Setz auch erstmal einen Haltepunkt auf Zeile 5, und guck nach, wie .InsertCommand.CommandText überhaupt lautet.
    Nicht dass es iwelchen schönen Blödsinn ergibt, wenn man "Select" durch "Replace" replaced.



    ach- zu deiner Frage nach dem Fehler in Post#7:
    DataAdapter.Update(table) updated immer die ganze Table.
    Wenn die einmal geupdated ist, dann sind alle ihre DataRows auf DataRowstate.Unchanged gesetzt - auf diese Weise merkt sich das Dataset, dass diese DataRows bereits geupdated sind, und nicht nochmal geupdated werden müssen.
    Wenn du also in einer Schleife immer wieder DataAdapter.Update(table) aufrufst, passiert beim zweiten mal garnix, weil alle DataRows der DataTable als bereits geupdated gekennzeichnet sind.
    Nur zur Erklärung - zu fixen gibts da nix.

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()