DataSet über TableAdapterManager in DB, wie neue DB-Schlüssel einlesen?

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

Es gibt 4 Antworten in diesem Thema. Der letzte Beitrag () ist von DahProgrammah.

    DataSet über TableAdapterManager in DB, wie neue DB-Schlüssel einlesen?

    Moin,

    ich habe ein DataSet mit mehreren Tabellen und Relationen. Irgendwann speichert man nach diversen Änderungen (Neuanlage, Löschen, Bearbeiten) und ruft dazu das .Validate() auf, ein .EndEdit() auf alle Bindingsources und lässt mit TableAdapterManager.UpdateAll() alles in der Datenbank (MySql) speichern.
    Danach habe ich aber immer noch meine in den Tables des Datasets erzeugten Primärschlüssel von z.B. -1, -2 usw. in den Rows und nicht die Primärschlüssel aus der Datenbank, die ein AutoIncrement hat und daher andere Schlüssel anlegt (10, 20...).
    Wie macht Ihr das, wenn Ihr im DataSet nicht noch eine Weile mit den negativen Schlüsseln weiterarbeiten wollt, sondern gerne die Schlüssel der Datenbank im Speicher haben möchtet?
    Ich kann nach dem Speichern natürlich alle betroffenen Tabellen mit .Fill() wieder neu aus der DB holen, dann habe ich die DB-Primärschlüssel. So mache ich das aktuell auch.
    Gibt es da auch eine andere Möglichkeit - irgendeine Einstellung, dass das TableAdapterManager.UpdateAll() die neuen Schlüssel automatisch aus der DB holt und in die Datensätze übernimmt?
    Dass das in Ausnahmefällen für einzelne Datensätze mit LastInsertedID o.ä. geht, ist mir klar, aber damit will ich erst gar nicht anfangen - so highlevel und vom Framwerk unterstützt wie möglich.

    Danke & einen schönen Tag noch!
    Gruß
    Michael
    nee - das stimmt schon.
    Beim Inserten mit DataAdaptern generiert die Datenbank eigene Primkeys. Und die müssen zurück-abgefragt und ins Dataset eingepflegt werden, denn die IDs müssen ja identisch zu denen der Db sein.

    Der Vorgang ist sehr umständlich, aber machbar.
    Ich habe eine lightweigth- Lösung und eine sehr mächtige gebastelt, gugge
    Dataset->Db

    allgemeine Zugriffs-Lösung für: MySql, Access, SqlCe, SqlServer, DatasetOnly

    Ganz fleissige können das PrimKey-Requery auch selber coden, für jede Tabelle einzeln:
    Auslesen des neuen Wertes der Schlüsselspalte nach dem Erstellen eines neuen Datensatzes mit @@Identity
    Vielen Dank schon mal vorab, habe ich mir gedacht, dass dazu mal wieder Kreativität gefragt ist - wäre auch zu schön gewesen.
    @EDR, danke, ich werde mir das anschauen, aber die Einzeldatensatz-Nachbearbeitung wird es sicher nicht werden, da bleibe ich lieber bei meinem .Fill() nach dem .UpdateAll().
    @VB1963: ich habe mit dem Schlüssel nix vor, aber wenn schon Kopie der DB im Speicher, dann doch bitte eine aktuelle, wenn sich eine größere Menge Daten geändert hat. Die Daten an sich sind ja gleich, aber eben die Schlüssel nicht - gefällt mir nicht an dem ganzen Konzept.
    Hallo zusammen,

    Problem gefunden und erfolgreich einen Workaround gebaut.

    Ursache: ein seit mind. Juli 2008 in "MySQL for Visual Studio" (genauer im .NET-Connector) befindlicher Bug, der scheinbar auch nicht so einfach zu bereinigen ist, da Microsoft die ganze TabelAdapter/TableAdapaterManager-Sache mit Hauptfokus MS-SQL-Server entwickelt hat und MySQL es daher etwas schwerer hat, sich einzuklinken.

    Der Bug ist beschrieben z.B. hier: bugs.mysql.com/bug.php?id=37865 oder hier: bugs.mysql.com/bug.php?id=70305.

    Für MS-SQL ist standardmäßig im "TableAdapter-Konfigurations-Assistent" unter "Erweiterte Optionen" ein Haken bei "Datentabelle aktualisieren" gesetzt. Dort steht:
    "Fügt eine Select-Anweisung nach Insert- und Update-Anweisungen hinzu, um Identitätsspalten-, Standard- und andere Werte abzurufen, die von der Datenban berechnet werden."

    Bei einer MsSql-DB-Anbindung ist der Haken bis dato nicht gesetzt. Setzt man ihn und lässt den Assistenten durchlaufen, ist er wieder entfernt und der erwünschte SQL-Code, dass nämlich nach dem Einfügen der von der DB generierte PK in die Datensätze zurückgeschrieben wird, steht leider auch nicht z.B. im InsertStatement - das ist der Bug von oben. Bei MS-SQL sieht der erzeugte Code z.B. so aus:

    SQL-Abfrage

    1. INSERT INTO [dbo].[Child] ([MasterID], [PosBezeichnung]) VALUES (@MasterID, @PosBezeichnung);
    2. SELECT ID, MasterID, PosBezeichnung FROM Child WHERE (ID = SCOPE_IDENTITY())


    Bis der Bug mal entfernt wird, kann man sich so behelfen, wie im ersten o.g. Link geschrieben:

    Z.B. beim Form-Laden die Fix-Methode je Tableadapter aufrufen. Übergeben wird der Adapter eines jeden TableAdapters und die Primärspalte der Zieltabelle des Tableadapters.

    VB.NET-Quellcode

    1. FixDataAdapterInsertCommand(Me.MasterTableAdapter1.Adapter, MasterchildtestDataSet.master.idColumn)
    2. FixDataAdapterInsertCommand(Me.ChildTableAdapter1.Adapter, MasterchildtestDataSet.child.idColumn)


    Die Fix-Methode selbst:

    VB.NET-Quellcode

    1. Public Shared Sub FixDataAdapterInsertCommand(ByVal adapter As MySqlDataAdapter, ByVal autoIncrementColumn As DataColumn)
    2. Dim finalSelect As String = ";SELECT last_insert_id() AS '" & autoIncrementColumn.ColumnName & "'"
    3. If adapter.InsertCommand.CommandText.IndexOf("last_insert_id()") >= 0 Then
    4. Throw New ArgumentException("adapter.InsertCommand is already fixed")
    5. End If
    6. adapter.InsertCommand.CommandText &= finalSelect
    7. adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.FirstReturnedRecord
    8. End Sub


    Danach steht - wie bei MS-SQL - auch nach dem folgenden Code in allen Tabellen der PK aus der Datenbank drin (und nicht mehr die -1, -2... Werte von zuvor) - ohne dass man die Daten mit .Fill() neu nachladen musste.

    VB.NET-Quellcode

    1. Me.Validate()
    2. Me.MasterBindingSource1.EndEdit()
    3. Me.ChildBindingSource1.EndEdit()
    4. Me.TableAdapterManager1.UpdateAll(Me.MasterchildtestDataSet)


    Fehlermeldungen dieser Art (der Foreign-Key des Childs wurde mit z.B. -1 in die DB geschrieben, da nicht durch den korrekten Key des Masters ersetzt) verschwinden dann auch:
    Cannot add or update a child row: a foreign key constraint fails (`userarea`, CONSTRAINT `iduser_1` FOREIGN KEY (`iduser`) REFERENCES `user` (`iduser`) ON DELETE CASCADE ON UPDATE CASCADE)

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