Sqlite UpdateCommand

  • C#
  • .NET (FX) 4.0

Es gibt 17 Antworten in diesem Thema. Der letzte Beitrag () ist von ErfinderDesRades.

    Sqlite UpdateCommand

    Hallo,
    ich bin ganz neu hier. Bisher habe ich nur gelesen.
    Seit ein paar Tagen hänge ich an einem Problem mit Sqlite.
    Ich baue eine funktionierende Anwendung um von MsSql auf Sqlite.
    Ein einfaches Updatecommand funktioniert nicht so wie bei MSSql:

    SQLiteCommandBuilder commandBuilderL = new SQLiteCommandBuilder(sldTiereOne);
    sldTiereOne.UpdateCommand = commandBuilderL.GetUpdateCommand();
    sldTiereOne.InsertCommand = commandBuilderL.GetInsertCommand();
    sldTiereOne.Update(tblTiereOne);


    Da gibt es eine Fehlermeldung:
    Parallelitätsverletzung: Der UpdateCommand hat sich auf 0 der erwarteten 1 Datensätze ausgewirkt.

    Meine Frage ist: kann ich mir das fertige UpdateCommand irgendwie zeigen lassen, um es dann manuell auszuführen?
    Was ich sehen kann ist immer das Updatecommand mit den ganzen @Parametern. Das nützt mir nichts.
    Kann jemand helfen?

    Grüße Ulf
    Wenn ich das richtig interpretiere, müsste sldTiereOne.UpdateCommand.CommandText zum Ziel führen, siehe docs.microsoft.com/de-de/dotne…?view=dotnet-plat-ext-5.0

    EDIT: Evtl. aber auch nicht ... Siehe Post #5 in diesem Thread: forums.asp.net/t/1351973.aspx?…ameters+value+in+debugger

    Da gibt es eine Funktion, die das gewünschte erreicht.
    Besucht auch mein anderes Forum:
    Das Amateurfilm-Forum

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Marcus Gräfe“ ()

    Hallo Markus,
    danke für die schnelle Antwort.
    Ja, da hätte ich auch von alleine drauf kommen können.
    So ist das wenn man stundenlang auf die gleiche Stelle guckt.
    Mein Problem scheint aber ein anderes zu sein. Jetzt kann ich sehen, dass im UpdateCommand gar nichts drin steht.
    Da werde ich aber erstmal selbst weiter forschen.
    Vielen Dank erstmal

    Grüße Ulf
    das widerspricht der Fehlermeldung:
    Der UpdateCommand hat sich auf 0 der erwarteten 1 Datensätze ausgewirkt.

    Hängt mit dem CommandBuilder zusammen - das ist ein magisches undurchsichtiges Teil.
    probierma

    C#-Quellcode

    1. var cmd = commandBuilderL.GetUpdateCommand();

    ob dann in cmd ein Command ankommt, was du debuggen kannst.
    Hallo,

    mit GetupDateCommand sehe ich wieder nur das Command mit den Parametern,
    aber nicht den Inhalt und die Details der Exeption beim Update sagen nicht, an welchem Feld sich das aufhängt

    UPDATE [main].[sqlite_default_schema].[tiere] SET [id_art_tier] = @param1, [id_gender] = @param2, [id_mutter] = @param3,

    Grüße Ulf
    Der von dir zitierte CommandText ist unvollständig, da fehlen mindestens ein weiteres Feld, was auch gesetzt wird.
    Vor allem aber fehlt die Where-Klausel.

    natürlich bekommst du keine Angabe, dass es sich wegen eines Feldes irgendwo aufhängt.
    Die Fehlermeldung sagt, dass kein Datensatz gefunden wurde, auf den die Bedingung zutrifft.
    Der UpdateCommand hat sich auf 0 der erwarteten 1 Datensätze ausgewirkt.
    Es hängt sich also nirgends auf.
    Sondern er meldet, dass er einen Datensatz updaten wollte, aber den Datensatz nicht findet in der Datenbank.



    grad eine neue Idee:

    C#-Quellcode

    1. SQLiteCommandBuilder commandBuilderL = new SQLiteCommandBuilder(sldTiereOne);
    2. sldTiereOne.UpdateCommand = commandBuilderL.GetUpdateCommand();
    3. sldTiereOne.InsertCommand = commandBuilderL.GetInsertCommand();
    4. sldTiereOne.Update(tblTiereOne);
    Zeilen #2,#3 sind überflüssig.
    Aufgrund der Magie des CommandBuilders wirken die Commands des CommandBuilders auf den Adapter auch ohne diese Zuweisungen.
    Vielleicht sind diese redundanten Command-Zuweisungen bei SqLite sogar fehlerverursachend, weil dann iwie dasselbe Command zweimal ausgeführt wird.
    Das würde zur Fehlermeldung passen (wenn das vollständige Command so ist, wie ich es kenne, wie CommandBuilder sie defaultmässig generieren).

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

    Hallo,

    mit dem Weglassen der beiden Zeilen hast Du wohl Recht. Ich habe das aus einem Tutorial übernommen.
    Bei MsSql müssen die beiden Zeilen auch da sein, sonst funktioniert es nicht. Allerdings komme ich ohne die beiden Zeilen bei Sqlite
    zum gleichen Ergebnis:

    System.Data.DBConcurrencyException: "Parallelitätsverletzung: Der UpdateCommand hat sich auf 0 der erwarteten 1 Datensätze ausgewirkt."

    Aber ich gebe nicht auf und forsche weiter. Das wurmt mich einfach. Weil ich sonst das komplette Statement manuell aufbauen müsste.
    Das ist viel Mehraufwand. Die Anwendung soll wahlweise mit MsSql oder Sqlite laufen. In MsSql funktioniert das einwandfrei:

    C#-Quellcode

    1. private void BtnSave_Click(object sender, RoutedEventArgs e)
    2. {
    3. // int liAdd = 0;
    4. string lsMsg = "";
    5. switch (giDb)
    6. {
    7. case 1:
    8. SqlCommandBuilder commandBuilder = new SqlCommandBuilder(sdTiereOne);
    9. sdTiereOne.UpdateCommand = commandBuilder.GetUpdateCommand();
    10. sdTiereOne.InsertCommand = commandBuilder.GetInsertCommand();
    11. sdTiereOne.Update(tblTiereOne);
    12. lsMsg = "Datensatz geändert!";
    13. break;
    14. case 2:
    15. SQLiteCommandBuilder commandBuilderL = new SQLiteCommandBuilder(sldTiereOne);
    16. //sldTiereOne.UpdateCommand = commandBuilderL.GetUpdateCommand();
    17. //sldTiereOne.InsertCommand = commandBuilderL.GetInsertCommand();
    18. var cmd = commandBuilderL.GetUpdateCommand();
    19. sldTiereOne.Update(tblTiereOne);
    20. lsMsg = "Datensatz geändert!";
    21. break;
    22. default:
    23. break;
    24. }
    25. MessageBox.Show(lsMsg);


    Ich hatte hier nicht das komplette Statement reingepackt. Es sollte nur verdeutlichen, dass die Parameter anstelle der eingesetzten Werte gezeigt werden:
    UPDATE [main].[sqlite_default_schema].[tiere] SET [id_art_tier] = @param1, [id_gender] = @param2, [id_mutter] = @param3, [id_vater] = @param4, [nr_de] = @param5, [dt_geb] = @param6, [name] = @param7, [generation] = @param8, [id_art_rasse] = @param9, [id_art_zeugung] = @param10, [id_gewerk] = @param11, [dt_gekauft] = @param12, [id_import] = @param13, [dt_verkauft] = @param14, [preis_vk] = @param15, [preis_ek] = @param16, [gewicht_vk] = @param17, [bemerkung] = @param18, [id_verbleib] = @param19, [dt_tod] = @param20, [id_standort] = @param21, [id_kunde] = @param22, [id_tragend] = @param23, [id_kennung] = @param24 WHERE (([id_tier] = @param25) AND ((@param26 = 1 AND [id_art_tier] IS NULL) OR ([id_art_tier] = @param27)) AND ((@param28 = 1 AND [id_gender] IS NULL) OR ([id_gender] = @param29)) AND ((@param30 = 1 AND [id_mutter] IS NULL) OR ([id_mutter] = @param31)) AND ((@param32 = 1 AND [id_vater] IS NULL) OR ([id_vater] = @param33)) AND ((@param34 = 1 AND [nr_de] IS NULL) OR ([nr_de] = @param35)) AND ((@param36 = 1 AND [dt_geb] IS NULL) OR ([dt_geb] = @param37)) AND ((@param38 = 1 AND [name] IS NULL) OR ([name] = @param39)) AND ((@param40 = 1 AND [generation] IS NULL) OR ([generation] = @param41)) AND ((@param42 = 1 AND [id_art_rasse] IS NULL) OR ([id_art_rasse] = @param43)) AND ((@param44 = 1 AND [id_art_zeugung] IS NULL) OR ([id_art_zeugung] = @param45)) AND ((@param46 = 1 AND [id_gewerk] IS NULL) OR ([id_gewerk] = @param47)) AND ((@param48 = 1 AND [dt_gekauft] IS NULL) OR ([dt_gekauft] = @param49)) AND ((@param50 = 1 AND [id_import] IS NULL) OR ([id_import] = @param51)) AND ((@param52 = 1 AND [dt_verkauft] IS NULL) OR ([dt_verkauft] = @param53)) AND ((@param54 = 1 AND [preis_vk] IS NULL) OR ([preis_vk] = @param55)) AND ((@param56 = 1 AND [preis_ek] IS NULL) OR ([preis_ek] = @param57)) AND ((@param58 = 1 AND [gewicht_vk] IS NULL) OR ([gewicht_vk] = @param59)) AND ((@param60 = 1 AND [bemerkung] IS NULL) OR ([bemerkung] = @param61)) AND ((@param62 = 1 AND [id_verbleib] IS NULL) OR ([id_verbleib] = @param63)) AND ((@param64 = 1 AND [dt_tod] IS NULL) OR ([dt_tod] = @param65)) AND ((@param66 = 1 AND [id_standort] IS NULL) OR ([id_standort] = @param67)) AND ((@param68 = 1 AND [id_kunde] IS NULL) OR ([id_kunde] = @param69)) AND ((@param70 = 1 AND [id_tragend] IS NULL) OR ([id_tragend] = @param71)) AND ((@param72 = 1 AND [id_kennung] IS NULL) OR ([id_kennung] = @param73)))

    Grüße Ulf

    Dieser Beitrag wurde bereits 6 mal editiert, zuletzt von „namdi“ ()

    namdi schrieb:

    Bei MsSql müssen die beiden Zeilen auch da sein, sonst funktioniert es nicht.
    Das ist bei mir anders - bei mir braucht mssql diese Zeilen nicht.

    Zum Statement: Jo, so kenne ich die Statements, die defaultmässig vom CommandBuilder gebaut werden. Die prüfen ab, ob der Datensatz zwischenzeitlich geändert wurde, und updaten nur, wenn das nicht der Fall ist.
    Findet sich eine Änderung, so wird die Db nicht geupdated, und der DataAdapter merkt das und schmeisst den Fehler: "Das UpdateCommand hat sich auf 0 Datensätze ausgewirkt - erwartet wurde aber, dass 1 Datensatz geändert wird."

    Naja - wenns da nicht dran liegt, dann woanders.
    Als nächstes wäre zu prüfen, ob der SqlCommandBuilder vielleicht ein anderes UpdateCommand generiert. Ist ja verdächtig, dass er das scheinbar nicht abzuprüfen scheint.

    Dann gibts noch einiges anderes zu sagen, etwa dass du disposable nicht disposest, und dass du den DataAcces scheinbar nicht an einem Punkt konzentriert hast, wo man Kontrolle hätte über was abgespeichert wird.
    Könnte ja auch sein, dass der Datensatz schon an anderer Stelle abgespeichert wurde.

    Vor allem vermute ich jetzt eine unsachgemässe Verwendung von .AcceptChanges, die du evtl. auch aus ieinem Tutorial übernommen hast.
    Aber eins nachm anderen.
    Ich habe den Fehler gefunden. Mühsam habe ich alle Felder der Tabelle aus dem lesenden SQL-Statement, dem Xaml und dem Programm rausgenommen ud alles
    schrittweise wieder eingefügt. Der Fehler lag in der Datenbank. Ich habe die Daten aus MsSql importiert. Dabei wurden Felder, die den Wert null hatten, mit dem Wert "NULL" beschrieben.

    Die habe ich dann bearbeitet. Für ein Feld habe ich das übersehen. Da ware noch ein paar "Null"-Werte mit dem Befehl:

    SQL-Abfrage

    1. UPDATE tiere Set id_import = NULL Where id_import = "NULL";

    ging das zu korrigieren. Das Feld ist ein Integer. Mich wundert, dass die Datenbank das beim Import nicht angemeckert hat.
    Nun läuft das perfekt. Du hast doch Recht. Es geht auch bei MsSql ohne die Updatecommands. Wieder was gelernt.
    Vielen Dank für Hilfe und Anregungen. Ich hoffe, ich kann auch mal weiterhelfen.

    Grüße Ulf
    Mist, das ärgert mich jetzt fast.
    Das hatte ich vor paar Wochen schonmal, dass jemand von einem DB-System auf ein anderes umgestiegen ist, und bestimmte Dinge falsch übertragen wurden.

    Zu deim Integer-Feld das glaub ich auch nicht, dass das i.o. ist. Ich nehme an, SqLite hat dem Feld jetzt den Datentyp varchar verpasst.
    Dabei sollte es unbedingt int bleiben.
    Das solltest du nicht auf sich beruhen lassen. Überhaupt sollte das Feld höchstwahrscheinlich nicht Nullable sein - ist es jetzt aber doch.
    Ich gehe davon aus, das Feld ist ein Fremdschlüssel, und da muss man schon sehr gute Gründe haben, wenn man einen Fremdschlüssel Nullable haben will.
    Was ist im konkreten Fall bei dir der Grund?
    Man kann Daten aus einem Excel-Blatt importieren. Der Import wird protokolliert in einer anderen Tabelle. Wenn man sich versehen hat oder Murks im Import steht, kann man das ganze anhand der Import-id wieder rückgängig machen. Also: manuell eingegebene Daten haben keine import_id (null).
    Das Feld ist im SQLite integer geblieben aber es stand "NULL" drin (importiert als csv). :D

    Grüße Ulf
    Ah - ok, so ergibt ein nullable ForeignKey Sinn.


    namdi schrieb:

    Das Feld ist im SQLite integer geblieben aber es stand "NULL" drin (importiert als csv).
    Da stimmt was nicht. In einer int-Spalte kann nicht "Null" drinne stehen. Einzige Möglichkeit, dass da Null drinne ist, und dein Debugger das iwie als "Null" präsentiert.
    Aber um ganz sicher zu gehen, probier mal, ob du, wo vorher "Null" gestanden ist, ob du da "Nils" eintragen kannst.
    Wenn da wirklich "Null" steht, dann kann man da auch "Nils" eintragen.
    Allerdings ist die Spalte dann kein int - egal was wer auch immer erzählt.
    Hallo,

    in diesem Beitrag hatte ich ein Bild drin. Da kannst Du es sehen. Das ist aus dem DB-Browser Sqlite
    dropbox.com/s/h1a7opx6drxoj5c/updateCommandNull.jpg?dl=0

    und das sind die zugehörigen Tabelleninfos:
    dropbox.com/s/h1a7opx6drxoj5c/updateCommandNull.jpg?dl=0


    Grüße Ulf

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

    jo - so Bilder guck ich ja nicht an - wer weiss was für Web-Corona-Krönchen mir da aufgesetzt werden.
    vbParadise hat eine super-Datei-Anhäng-Funktion, da kann man auch Bilder anhängen



    achso, das war dropbox. aber die müssen auch ihr geld verdienen.
    habich aber auch garnet erkannt, dass da was zu sehen gab.

    Das zweite bildle , aus post#13 kann ich garnet angugge.

    Das Dropbox-Bild sieht jdfs. wirklich aus wie eine varchar-Spalte, und da solltest du mal einen Datensatz mit "Nils" updaten.
    Nils geht auch (mit DbBrowser für Sqlite reingeschrieben)

    dropbox.com/s/tg7aijws9waptit/nils.jpg?dl=0

    und auch mit dem Sql-Statement:

    SQL-Abfrage

    1. Update tiere set id_import="NILS" WHERE id_import = "NULL"


    dropbox.com/s/njvs3skptnrrnyw/nils2.jpg?dl=0

    Sorry, aber bei der Anwahl des Bild Icons erscheint auch nur die Frage nach einer URL

    Grüße Ulf

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

    tja, eine Spalte, in die man "Nils" eintragen kann ist definitiv nicht vom Typ int.
    Ich würd das nicht auf sich beruhen lassen, schon um rauszufinden, wie das passieren konnte, und wie man sowas in Zukunft vermeidet.



    Zum Bilder-Upload: Bitte guck das hiermit nun zum dritten Mal gegebene Tut auch mal an:
    Wenn du genau hinguckst siehst du etwas, was entfernt wie ein Button aussieht, oder?
    Und da steht etwas drauf: "Klick mich!". Wenn du das einfach mal tun tätest...

    Im Tut wird gezeigt, wie man auf vbp ein Bild einfügt - es geht nicht über den belämmerten Bild-Icon.