Announcement

Collapse
No announcement yet.

Update bei Master/Detail geht nicht

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

  • Update bei Master/Detail geht nicht

    Hallo!

    Ich habe meine Frage bereits am 12.06.2006 veröffentlicht. Anscheinend konnt (wollte) mir keiner helfen.

    Mein Problem besteht im Update einer Master-Detail Tabelle.

    Das Beispiel aus der MS Hilfe habe ich genau so für meine Anwendung benutzt, jedoch gibt es keine Erfolg.

    Es werden zunächst mit GetChanges die Änderungen ermittelt (Deleted, Added und Modified). Anschließend werden diese Daten über Update an die Datenbank übertragen.

    Leider gibt GetChanges eine Kopie der Daten zurück, dadurch wird mein Primärschlussel in der andern Tabelle nicht aktuallisiert.
    In der durch GetChanges erzeugten Tabelle ist der Primärschlüssel enthalten.

    Ergebnis: nicht gut.

    Wie aktuallisiere ich eine Master-Detail-Beziehung?????

    Gibt es nicht ein lauffähiges Beispiel?

    mfg
    Thomas

  • #2
    Kann deinem Problem nicht ganz folgen.

    Wenn du einfach das Dataset aus GetChanges mit den korrigierten PKs in das echte Datasets zurückmergst via Dataset.Merge(GetChangesDataset) sollte das eigentlich passen.

    Ral

    Comment


    • #3
      Hallo!

      So trifft man sich wieder!

      Mit Merge habe ich es bereits versucht, jedoch wurde hierdurch ein zusätzlicher Datensatz in meine Tabelle eingetragen, und zwar die welche den geänderten Primärschlüssel enthält. Jedenfalls sagt mit das die DataSet Schnellansicht.

      Bei mir ist die Lage mit der aktuallisierung noch etwas komplexer da ich sogar vier Tabellen bearbeite, welche hintereinander abhängig sind.

      Tab1->Tab2->Tab3->Tab4.

      Primärschlüssel Tab1 ist Fremdschlüssel in Tab2.
      Primärschlüssel Tab2 ist Fremdschlüssel in Tab3.
      usw.

      Zusätzliche Schwierigkeit:

      Alle Tabellen müssen bearbeitet werden und wenn der Benutzer dann entscheidet - alles OK - dann werden die Daten alle gespeichert. Hierbei kann es vorkommen, das der Bediener seine Entscheidungen bezüglich einträge in Tab2 und Tab3 mehrfach ändert.

      Kann man mir noch helfen?

      mfg
      Thoma

      Comment


      • #4
        Hallo,
        je genauer die Formulierung der Frage, umso höher ist die Wahrscheinlichkeit der Antwort :-)

        Angenommen, die Tabellen verwenden einen INT als Primärschlüssel, dessen Wert in der Datenbank über <i>IDENTITY</i> (MS SQL Server) automatisch vergeben wird. Wenn in Visual Studio ein typisiertes DataSet angelegt wird, hat die Primärschlüsselspalte den Wert True in der Eigenschaft <b>AutoIncrement</b>. Im <i>XML Schema Designer</i> wird das typisierte DataSet nun so konfiguriert, dass alle Primärschlüsselspalten die Eigenschaften <b>AutoIncrementSeed</b> und <b>AutoIncrementStep</b> auf den Wert <b>-1</b> setzen. Damit ist garantiert, dass alle vom Anwender neu im DataSet angelegte Datensätze durch die <b>negativen</b> Primärschlüsselwerte niemals mit den "echten" Primärschlüsselwerten in den Datenbanktabellen kollidieren. Wenn dann das DataSet über die <b>Update</b>-Methode des Adapters (SqlDataAdapter oder typisierter TableAdapter) in die Datenbank zurückgeschrieben wird, aktualisiert der SQL Server die IDENTITY-Spalten in eigener Regie. Das zurückgelieferte DataSet enthählt nun die neuen Primärschlüsselwerte, die über die Methode <b>Merge</b> in das originale DataSet eingespielt werden können, damit die echten Primärschlüsselwerte bekannt sind. Allerdings werden nur die Datensätze aktualisiert, deren Primärschlüsselwert in beiden DataSet-Instanzen gleich sind, alle anderen werden neu eingefügt. Folge: Die neuen Datensätze tauchen doppelt auf.

        Damit dieses Problem verschwindet, muss das Programm unmittelbar vor dem Merge-Aufruf die alten Datensätze mit dem Statuswert <b>DataViewRowState.Added</b> durch den Aufruf von <b>Remove</b> entfernen. Das folgende Beispiel demonstriert dies, indem zur visuellen Verdeutlichung die unterschiedlichen Zustände in mehreren DataGrids angezeigt und in einer ListBox protokolliert werden:

        <div style="font-family: Courier New; font-size: 10pt; color: black; background: white; border-top: windowtext 1pt solid; padding-top: 0pt; border-left: windowtext 1pt solid; padding-left: 0pt; border-right: windowtext 1pt solid; padding-right: 0pt; border-bottom: windowtext 1pt solid; padding-bottom: 0pt;"><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Dim</span> aDSChanges <span style="color: blue;">As</span> DataSet</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Private</span> <span style="color: blue;">Sub</span> ButtonFill_Click(<span style="color: blue;">ByVal</span> sender <span style="color: blue;">As</span> System.Object, <span style="color: blue;">ByVal</span> e <span style="color: blue;">As</span> System.EventArgs) <span style="color: blue;">Handles</span> ButtonFill.Click</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Me</span>.SqlDataAdapter1.Fill(<span style="color: blue;">Me</span>.DataSet11)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StatusBar1.Text = <span style="color: maroon;">"DataSet-Methode Fill wurde aufgerufen"</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Sub</span></p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Private</span> <span style="color: blue;">Sub</span> ButtonInsert_Click(<span style="color: blue;">ByVal</span> sender <span style="color: blue;">As</span> System.Object, <span style="color: blue;">ByVal</span> e <span style="color: blue;">As</span> System.EventArgs) <span style="color: blue;">Handles</span> ButtonInsert.Click</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Dim</span> iLoop <span style="color: blue;">As</span> <span style="color: blue;">Integer</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Dim</span> aNewRow <span style="color: blue;">As</span> DataRow</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">With</span> DataSet11.Tables(0)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">For</span> iLoop = 1 <span style="color: blue;">To</span> 5</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; aNewRow = .NewRow()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; aNewRow(1) = <span style="color: maroon;">"Neu "</span> + iLoop.ToString()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; .Rows.Add(aNewRow)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; System.Diagnostics.Debug.WriteLine(<span style="color: maroon;">"Row hinzufügt: "</span> + iLoop.ToString())</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Next</span> iLoop</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">With</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StatusBar1.Text = <span style="color: maroon;">"DataSet-Kollektion Rows wurde mit neuen Daten gefüllt."</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Sub</span></p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Private</span> <span style="color: blue;">Sub</span> ButtonGetChanges_Click(<span style="color: blue;">ByVal</span> sender <span style="color: blue;">As</span> System.Object, <span style="color: blue;">ByVal</span> e <span style="color: blue;">As</span> System.EventArgs) <span style="color: blue;">Handles</span> ButtonGetChanges.Click</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; aDSChanges = DataSet11.GetChanges()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; DataGrid2.DataSource = aDSChanges.Tables(0)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Sub</span></p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Private</span> <span style="color: blue;">Sub</span> ButtonUpdate_Click(<span style="color: blue;">ByVal</span> sender <span style="color: blue;">As</span> System.Object, <span style="color: blue;">ByVal</span> e <span style="color: blue;">As</span> System.EventArgs) <span style="color: blue;">Handles</span> ButtonUpdate.Click</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Dim</span> iRowsAffected <span style="color: blue;">As</span> <span style="color: blue;">Integer</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; iRowsAffected = SqlDataAdapter1.Update(aDSChanges)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; MessageBox.Show(<span style="color: blue;">String</span>.Format(<span style="color: maroon;">"Es wurden {0} Datensätze eingearbeitet."</span>, iRowsAffected))</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StatusBar1.Text = <span style="color: maroon;">"DataAdapter-Methode Update wurde aufgerufen"</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">' Ergebnis anzeigen</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Dim</span> aDSResult <span style="color: blue;">As</span> <span style="color: blue;">New</span> DataSet()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; SqlDataAdapter1.Fill(aDSResult)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; DataGrid3.DataSource = aDSResult.Tables(0)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Sub</span></p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">Private</span> <span style="color: blue;">Sub</span> ButtonMerge_Click(<span style="color: blue;">ByVal</span> sender <span style="color: blue;">As</span> System.Object, <span style="color: blue;">ByVal</span> e <span style="color: blue;">As</span> System.EventArgs) <span style="color: blue;">Handles</span> ButtonMerge.Click</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">' Zuerst die "alten Leichen" abräumen</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Dim</span> aTmpTable <span style="color: blue;">As</span> DataTable = DataSet11.Tables(0)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Dim</span> aTmpRow <span style="color: blue;">As</span> DataRow</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">For</span> <span style="color: blue;">Each</span> aTmpRow <span style="color: blue;">In</span> aTmpTable.Select(<span style="color: maroon;">""</span>, <span style="color: maroon;">""</span>, DataViewRowState.Added)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; ListBox1.Items.Add(<span style="color: maroon;">"Remove: "</span> + aTmpRow(0).ToString())</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; aTmpTable.Rows.Remove(aTmpRow)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">Next</span> aTmpRow</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">' Neue Primärschlüsselwerte in der Original-Datenmenge einarbeiten, ohne</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">' das die betroffenen DataRow-Instanzen als geändert gekennzeichnet werden</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; DataSet11.Merge(aDSChanges, <span style="color: blue;">False</span>)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">' Nach der Merge-Operation soll das DataSet als ungeändert betrachtet werden</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; DataSet11.AcceptChanges()</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; StatusBar1.Text = <span style="color: maroon;">"DataAdapter-Methode Merge wurde aufgerufen"</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; <span style="color: blue;">End</span> <span style="color: blue;">Sub</span></p></div>

        Bei einem typisierten DataSets sind die Beziehungen der Tabellen untereinander bereits bekannt (wenn auch die Datenbanktabellen einen Fremdschlüssel verwenden). Bei einem untypisierten DataSet muss die <b>Relations</b>-Kollektion selbst gefüllt werden, damit die Master-/Details-Abhängigkeit automatisch beim Zuweisen der neuen Primärschlüsselwerte berücksichtigt wird.
        &#10

        Comment


        • #5
          Vielen Dank!!!!!!!!

          An Hr. Kosch:
          Leider muss ich heute auf Dienstreise so das ich Ihr Beispiel noch nicht probieren kann. Werde mich aber gleich heute Abend darauf stürzen.
          Genau das sind die Feinheiten, über die ich in vielen Büchern über VS.NET oder ADO.NET keine Lösungen finde, die aber das leben schwierig machen. Genau solche Beispiele, die man eben nicht in der Online-Hilfe findet, schätze ich an Ihren Büchern.

          mfg
          Thomas Sparenber

          Comment


          • #6
            Hallo!

            So- jetzt bin ich soweit und kann eine Rückmeldung zu diesem Thema geben.

            Wie oben beschrieben habe ich mehrer Tabellen die "sequenziell" voneinander abhängig sind.

            Ein "löschen" eines Datensatzes und ein anschließender "Merge" schien nicht die Lösung zu bringen, da zu diesem Datensatz Äbhängigkeiten bestehen.

            Jedoch liegt die Lösung in dem Beispiel von Hr. Kosch.

            Ich habe folgendes realisiert:

            1. Löschen der Datensätze, beginnent mit der Client'sten-Tabelle .

            DataRow[] drsTab4 = this._AuftragDS.Tab4.Select("", "", DataViewRowState.Deleted);
            SqlDataAdapter4.Update(drsTab4)
            DataRow[] drsTab3 = this._AuftragDS.Tab3.Select("", "", DataViewRowState.Deleted);
            SqlDataAdapter3.Update(drsTab3)
            usw.

            2. Update der Master-Tabelle
            SqlDataAdapter1.Update();

            3. Insert der ClientTabellen. Beginnet mit der 1.Client-Tabelle bis zur Client'sten Tabelle.
            DataRow[] drsTab2 = this._AuftragDS.Tab2.Select("", "", DataViewRowState.Added);
            SqlDataAdapter2.Update(drsTab2)
            DataRow[] drsTab3 = this._AuftragDS.Tab3.Select("", "", DataViewRowState.Added);
            SqlDataAdapter3.Update(drsTab3)

            4. Update der Client-Tabellen. Beginnet mit der ersten Client-Tabelle.
            DataRow[] drsTab2 = this._AuftragDS.Tab2.Select("", "", DataViewRowState.ModifiedCurrent);
            SqlDataAdapter2.Update(drsTab2)
            DataRow[] drsTab3 = this._AuftragDS.Tab3.Select("", "", DataViewRowState.ModifiedCurrent);
            SqlDataAdapter3.Update(drsTab3)

            Durch dieses vorgehen habe ich das Problem gelöst. Jetzt fehlt eigentlich noch eine transaktionsgebundendes Update.

            Ich hoffe das jemand durch diesen Eintrag evtl. schneller zur Lösung kommt als ich. Bei mir hat dieses Problem jedenfalls zur Ernüchterung beigetragen.

            mfg
            Thomas Sparenber

            Comment

            Working...
            X