Announcement

Collapse
No announcement yet.

DataSet.TableAdapter Insert mit GUID ( Access2013 )

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

  • DataSet.TableAdapter Insert mit GUID ( Access2013 )

    Hallo,

    Ich habe die typische Fehlermeldung System.Data.NoNullAllowedException: Spalte 'ID' lässt nicht 'nulls' zu.
    Viele Suchergebnisse habe ich bereits durchgelesen, aber keines hat mir wirklich geholfen, das Problem zu lösen.


    Grundlagen zur Fragestellung
    Ich erstelle in VS 2010 eine C# WindowsForm-Anwendung, auf der sich ein DataGridView ( dgvAdressen ) befindet.
    Als Datenquelle nutze ich eine AccessDB ( .mdb ), da es bei Verwendung eines SQL Server 2012 Express bereits am Verbindungsaufbau scheitert ( selbst mit sa keine Chance ).

    Nun habe ich zunächst über Projekt -> Klasse hinzufügen eine typisierte neue DataSet-Klasse zugefügt ( adressenDataSet ).
    Im Designer habe ich dann einen TableAdapter hinzugefügt und mir die Queries für UPDATE und INSERT generieren lassen.

    In der DataGridView dgvAdressen dann als Datenquelle die im DataSet adressenDataSet verfügbare Tabelle adressen ausgewählt.
    Wen wundert's, es werden mir im DGV alle Daten sauber angezeigt.


    Wo ist mein Problem
    Mein Problem liegt bei dem generierten INSERT-Befehl in Verbindung mit der GUID-Spalte ID in der AccessDB.
    Vor einigen Monaten hatte Ralf Jansen mir beim UPDATE-Problem bereits geholfen: Änderungen in DataGridView in Datenbank übernehmen
    Nun kommt aber hinzu, daß auch INSERTS über die Maske laufen sollen.

    Das Problem liegt wie gesagt in der ID-Spalte, die als ReplikationsID ( GUID ) in Access definiert wurde.
    Die DGV generiert aber logischerweise keine eindeutige GUID, so daß er natürlich ein Problem beim INSERT hat ( siehe oben ).


    Meine Frage
    Welche Möglichkeiten habe ich jetzt, neue Rows über die DGV sauber in die DB-Tabelle zurückzuschreiben.
    Die Verwendung soll nach Möglichkeit ohne weiteren Button beibehalten bleiben. Ich möchte gerne beim Verlassen der neuen DS-Zeile auf die INSERT-Query des TableAdapter zurückgreifen.
    Ich komme da einfach nicht weiter und habe bereits Stunden mit Suchen und nachvollziehen verbracht.


    Danke
    Zuletzt editiert von Arne Drews; 12.04.2015, 14:04.
    PHP rocks!
    Eine Initiative der PHP Community

  • #2
    Das Grid hat einen DefaultValuesNeeded Event

    Comment


    • #3
      Hallo Ralf,

      Danke wieder mal für den guten Tipp!

      Das hatte ich nicht mal bei meinen Suchen im Netz gefunden...
      Einziges Problem bleibt, welchen Wert ich für das GUID-Feld eintrage?
      Irgendeinen kann ich ja imho nicht nehmen, weils nicht der Konvention der GUID in Access entspricht.
      PHP rocks!
      Eine Initiative der PHP Community

      Comment


      • #4
        Ok, das war ja doch ein leichtes Spiel mit der GUID:
        Code:
        e.Row.Cells[0].Value = Guid.NewGuid();
        Allerdings werden die Daten nicht gespeichert ?! Der Insert-Command existiert, muß ich den noch irgendwie anstoßen?
        PHP rocks!
        Eine Initiative der PHP Community

        Comment


        • #5
          Wäre mir nicht bewusst.

          Um da einen sinnvollen Ratschlag zu geben ist der Weg zu lang vom Grid bis zum Update. Ich kann nur empfehlen das du das soweit debuggst das wir zumindest entscheiden können in welcher Richtung das Problem liegt. An der Stelle wo du den TableAdapter.Update aufrufst ist die DataTable mit den upzudaten Daten richtig gefüllt? Enthält die DataRow deine Guid?

          Comment


          • #6
            tableAdapter.Update funktioniert einwandfrei, dafür habe ich allerdings auch einen Button verwendet.
            Heißt, wenn man einen DS in der DGV ändert, muß man den Button klicken, der dann dies ausführt:
            Code:
            dgvAdressen.EndEdit();
            this.adressenTableAdapter.Update( this.adressenDataSet );
            Das habe ich durch die Tipps von Dir aus dem oben verlinkten Thema.

            Mein Problem beruht hier aber auf dem tableAdapter.Insert!
            Ich möchte, wenn ein weiterer Datensatz eingetragen wird, daß dieser automatisch - bei sagen wir mal weitergehen mit Tab - in die DB geschrieben wird.

            Klicke ich in die letzte Zeile, um einen neuen DS anzulegen, erscheint auch eine korrekte GUID in der entsprechenden Spalte.
            Meldungen usw. kommen auch nicht. Aber er schreibt nicht in die Tabelle zurück, daher meine Vermutung, daß irgendwo noch der Anstoß fehlt?!
            PHP rocks!
            Eine Initiative der PHP Community

            Comment


            • #7
              Zum Verständnis entsprechenden Code wie beim Button Click hast du aber schon irgendwo? Zum Beispiel in einem der Scroll Events des Grids (nicht das das die zwingend die richtige Stelle wäre ich hab noch nicht genau drüber nachgedacht)?

              Comment


              • #8
                Probiert habe ich das auf diese Weise:
                Code:
                this.adressenTableAdapter.Insert(
                        Guid.NewGuid(),
                        e.Row.Cells[1].ToString(),
                        e.Row.Cells[2].ToString(),
                        e.Row.Cells[3].ToString(),
                        e.Row.Cells[4].ToString(),
                        e.Row.Cells[5].ToString(),
                        e.Row.Cells[6].ToString(),
                        1
                    );
                in der EreignisMethode DataGridView_UserAddedRow.
                ( letzter Wert 1 manuell gesetzt, da grad kein Int-Cast möglich war )

                Dann hat er etwas zurück geschrieben, allerdings ein Objekt der Klasse DataGridViewTextBoxCell.
                Also habe ich das .ToString() mal auf den .Value angewendet:
                Code:
                this.adressenTableAdapter.Insert(
                        Guid.NewGuid(),
                        e.Row.Cells[1].Value.ToString(),
                        e.Row.Cells[2].Value.ToString(),
                        e.Row.Cells[3].Value.ToString(),
                        e.Row.Cells[4].Value.ToString(),
                        e.Row.Cells[5].Value.ToString(),
                        e.Row.Cells[6].Value.ToString(),
                        1
                    );

                , bekomme dann aber zur Laufzeit die Meldung
                Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt
                Lasse ich .ToString() weg, bekomme ich für alle String-Argumente bereits beim Erstellen des Projektes die Meldung:
                Argument kann nicht von "object" in "string" konvertiert werden.
                PHP rocks!
                Eine Initiative der PHP Community

                Comment


                • #9
                  Du willst über das DataGridView eine neue Row in der DataTable anlegen und doch nicht direkt in der Datenbank oder? Das mit der Insert Methode des Tableadapter macht so eigentlich gar keinen Sinn.
                  Das Grid wird automatische eine neue Row in der DataTable anlegen und du schreibst nochmal die Daten so direkt in die Datenbank an der DataTable vorbei. Später wenn du ein TableAdapter.Update machst werden alle uncommiteten Daten aus der DataTable in die Datenbank geschrieben also auch die Daten die du so schon per direktem Insert in die Datenbank geschrieben hast weil die Daten sind ja auch in der DataTable. Dann hast du die gleichen Daten (je nachdem wie du das machst dann mit verschiedenen IDs) 2 mal in der DB.

                  Falls das Missverständnis in der Benamsung der Tableadapter Update Methode liegt. Die zieht jede Änderung in der DB nach (Insert, Updates und Deletes) die macht nicht nur Updates.
                  Wofür du sorgen musst ist das das alle Felder auch gesetzt sind (wie zum Beispiel dein ID Feld) bevor TableAdapter Update aufgerufen wird. Zum Beispiel im UserAddedRow Event

                  Comment


                  • #10
                    Aha, dann habe ich das tatsächlich falsch verstanden. Ich dachte die Methode TableAdapter.Update wäre nur für Updates da.
                    Also würde es vermutlich reichen, die Methode in der DataGridView_UserAddedRow aufzurufen?!

                    Das teste ich nachher mal, danke!

                    Für mein Verständnis: Die Insert- und Update-Methoden, die bei dem typisierten Dataset im TableAdapter automatisch mit angelegt werden, kommen erst zum Einsatz, wenn ich dem TableAdapter explizit sage: .Update( <dataSet> )?
                    PHP rocks!
                    Eine Initiative der PHP Community

                    Comment


                    • #11
                      Bei der Update Methode mit DataSet werden die InsertCommand, UpdateCommand und DeleteCommand Commands direkt benutzt. Die Insert, Update, Delete Methoden denen man Einzeldaten geben kann kapseln nur das jeweilige Command udn befüllen die Parameter der Commands. Die werden aber selber vom TableAdapter nicht benutzt. Ich selbst kämme auch nie auf die Idee die zu benutzen. Diese Methoden gehen an DataTable, DataSet vorbei direkt auf die DB. Das ist ziemlich wiedersinnig für ein typisiertes DataSet wo natürlich alles durch das DataSet gehen sollte. Möglicherweise kann man beim anlegen des TableAdapters dem Designer sagen das der die erst gar nicht anlegen soll.

                      Comment


                      • #12
                        Ja, kann man dem Designer mitteilen.
                        Ok, ich hatte das ganze dann falsch verstanden. Ich probiere es nachher mal mit den neu gewonnenen Erkenntnissen.

                        Danke!
                        PHP rocks!
                        Eine Initiative der PHP Community

                        Comment


                        • #13
                          Funktioniert natürlich so wie Du sagtest, danke!
                          Zur Info für andere, das ( bzw. ein ) korrektes Ereignis heißt DataGridViw_RowPostPaint.


                          EDIT: RowPostPaint ist doch nicht so schlau. Sobald ich einen bestehenden Datensatz ändern möchte hängt er sich darin auf.
                          Neue einfügen geht damit wunderbar. Weißt Du zufällig, welches Ereignis nun sinnvoll ist, um Neue Datensätze als auch geänderte gleichbehandelt ans DataSet zu übergeben?
                          Ich behelfe mir zwar mit einem Button derzeit, aber ich würde es schöner finden, wenn ich die DGV live ändern/erweitern kann.
                          Zuletzt editiert von Arne Drews; 13.04.2015, 12:04.
                          PHP rocks!
                          Eine Initiative der PHP Community

                          Comment


                          • #14
                            Ich tendiere zu RowValidating. Da kannst du dann auch verhindern das man von der Row wegscrollt solange die noch unvollständig ist. Ob der auch feuert wenn die Form geschlossen wird und ob man dann mit einem Cancel in diesem Event auch das schließen der Form verhindern kann weiß ich nicht. Wenn dem nicht so ist müßtest du noch etwas entsprechenden im FormClosing Event der Form machen.

                            Comment


                            • #15
                              Hmmm... für Änderungen innerhalb der DGV bekomme ich permanent:
                              Für ein Update ist ein gültiger UpdateCommand erforderlich, wenn eine DataRow-Auflistung mit modifizierten Zeilen weitergegeben wird.
                              Einfügen einer neuen Zeile funktioniert weiterhin tadellos, allerdings auch nur über das ButtonClick-Event, nicht über RowValidating.

                              Habe ich damit irgendwie exotische Anforderungen, daß die DB live Ereignis gesteuert aus der DGV aktualisiert wird?
                              PHP rocks!
                              Eine Initiative der PHP Community

                              Comment

                              Working...
                              X