Announcement

Collapse
No announcement yet.

Aktuellen Primarykey vor dem Update aus der Datenbank holen

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

  • Aktuellen Primarykey vor dem Update aus der Datenbank holen

    Hallo,

    habe ein Problem mit einer Master Detail Beziehung und dem Primarykey.
    Ich arbeite mit dem SQL Server Express und Visual Studio 2005. In der Mastertabelle wurden bereits mehrfach Datensätze hinzugefügt und auch wieder gelöscht. Wenn ich nun in meinem Interface einen neuen Datensatz anlege, dann bekomme ich vom Dataset einen Primärschlüssel der nicht der aktuelle Schlüssel der Datenbank ist. Das ist noch kein Problem, denn beim zurückgeben an die Datenbank wird dieser sofort in meinem Formular geändert. Sobald ich aber das Detail Formular aktualisiere in dem noch die flasche Fremdschlüsselbeziehung steht erhalte ich eine Schutzverletzung.
    Kann mir jemand sagen wie ich den aktuellen Primärschlüssel von der Datenbank bekomme bevor ich das Update gegen die Datenbank fahre?

    Ps: Bin noch rellativ neu bei der Entwicklung mit ADO.Net

    Für Ihre Hilfe besten Dank im voraus!
    Mit freundlichen Grüßen
    Klaus-Dieter Held

  • #2
    Hallo,

    bei einer aktualisierbaren Master-/Detail-Tabellenbeziehung (referenzielle Integrität der Datenbank) muss man in der Tat die vom Visual Studio 2005-Wizard vorgenommene DataSet-Konfiguration ändern.
    Die Wizard-Voreinstellung optimiert für ReadOnly-Datenmengen, die nur in der Benutzeroberfläche angezeigt werden (d.h. die Reihenfolge der Fill-Aufrufe ist beliebig und die CPU-intensiven Constraint-Prüfungen entfallen). Der folgende Text beschreibt die Änderungen:

    Der Client soll über die Benutzeroberfläche im typisierten DataSet wohl neue Master- als auch zum neuen Masterdatensatz zugeordnete Detail-Datensätze anlegen. Das DataSet im Client kennt dabei jedoch nicht die Primär- und Fremdschlüssel, die später beim INSERT vom SQL Server vergeben werden. Daher muss das DataSet eigene Schlüssel generieren, die erst beim Einspielen in die Datenbank durch die echten Werte ersetzt werden. Dabei muss ADO.NET nach dem Einfügen eines Masterdatensatzes den erst dann feststehenden tatsächlichen Primärschlüsselwert automatisch in die betroffenen Fremdschlüsselplatzhalter der Detailtabelle übernehmen. Nur dann legt der SQL Server kein Veto ein, wenn die Detaildatensätze eingefügt werden.

    <div style="font-family: Consolas; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;"><span style="color: blue;">USE </span>TestDB</p><p style="margin: 0px;">GO</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;"><span style="color: blue;">CREATE TABLE </span>MasterTbl</p><p style="margin: 0px;">(</p><p style="margin: 0px;">&nbsp; mastertbl_id&nbsp; <span style="color: blue;">INT </span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; <span style="color: blue;">NOT NULL IDENTITY PRIMARY KEY</span>,</p><p style="margin: 0px;">&nbsp; mastervalue&nbsp;&nbsp; <span style="color: blue;">VARCHAR</span>(9) <span style="color: blue;">NOT NULL</span></p><p style="margin: 0px;">)</p><p style="margin: 0px;">GO</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;"><span style="color: blue;">CREATE TABLE </span>DetailTbl</p><p style="margin: 0px;">(</p><p style="margin: 0px;">&nbsp; detailtbl_id <span style="color: blue;">INT </span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; <span style="color: blue;">NOT NULL IDENTITY PRIMARY KEY</span>,</p><p style="margin: 0px;">&nbsp; mastertbl_id <span style="color: blue;">INT </span>&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; <span style="color: blue;">NOT NULL REFERENCES </span>MasterTbl(mastertbl_id),</p><p style="margin: 0px;">&nbsp; detailvalue&nbsp; <span style="color: blue;">VARCHAR</span>(9) <span style="color: blue;">NOT NULL</span></p><p style="margin: 0px;">)</p><p style="margin: 0px;">GO</p></div>

    Damit diese Aufgabe erfolgreich abgearbeitet wird, muss die von Visual Studio 2005 vorgenommene automatische Konfiguration im DataSet Designer geändert werden.

    a) Typisiertes DataSet einrichten

    b) Die beiden Tabellen im Server Explorer markieren und mit Drag&Drop auf den DataSet Designer ziehen

    c) Die Spalten für die beiden Primärschlüssel sind IDENTITY-Spalten. Damit die vom DataSet generierten lokalen Werte nicht mit den Datenbankwerten kollidieren, werden die beiden Eigenschaften AutoIncrementSeed und AutoIncrementStep auf -1 gesetzt. Alle im Offline-Betriebs des DataSets angelegten Datensätze erhalten negative Primärschlüsselwerte, so dass es später beim Update-Aufruf niemals zu Kollisionen mit bereits vorhandenen Werten kommen kann.

    d) Visual Studio kennzeichnet die Beziehung der referenziellen Integrität durch die Verbindungslinie. Wird die Line bearbeitet, müssen im Dialog Relation die folgenden Punkte geändert werden:
    1. Von Relation Only auf Both Relation and Foreign Key Constraint ändern
    2. UpdateRule, DeleteRule: Von None auf Cascade ändern
    3. AccessRejectRule: Auf den Defaultwert None belassen


    Kann mir jemand sagen wie ich den aktuellen Primärschlüssel von der Datenbank bekomme bevor ich das Update gegen die Datenbank fahre.
    Wenn die o.g. Änderungen eingearbeitet wurden, macht das ADO.NET ganz automatisch. Das Beispiel ist als ZIP-Archiv beigefügt
    Attached Files
    Zuletzt editiert von Andreas Kosch; 22.02.2007, 14:55.

    Comment


    • #3
      Hallo Herr Kosch,

      vielen Dank für die ausführlichen Erläuterungen.
      Ich werde es heute Abend einmal ausprobieren.

      Mit freundlichen Grüßen
      Klaus-Dieter Held

      Comment


      • #4
        Hallo Herr Kosch,

        das hat nun so funktioniert, allerdings bekomme ich jetzt beim löschen eines Datensatzes wieder eine Schutzverletzung. Was muß Ich denn hier noch einstellen. Ich arbeite mit den BindingNavigator

        Vielen Dank für Ihre Hilfe
        MfG
        Klaus-Dieter Held

        Comment


        • #5
          Hallo,

          beim Löschen von Datensätzen sind 2 Stellen beteiligt:

          a) CONSTRAINT der Datenbank, die eventuell selbst kaskadierend löscht
          b) DataSet-Regeln (DeleteRule der DataRelation im DataSet)

          Die DataSet-Konfiguration muss so gewählt werden, dass sie zur Datenbank-Konfiguration passt. Es macht einen Unterschied, ob in der Datenbank zum Beispiel die Option REFERENCES MasterTabelle(masterfeld) ON UPDATE CASCADE ON DELETE CASCADE genutzt wird.

          Wenn die Tabellen in der SQL Server-Datenbank über referenzielle Integrität miteinander verbunden sind (was generell der Fall sein sollte) aber dort nicht kaskadierend gelöscht wird, gelten bestimmte Regeln:

          1. Es kann nur dann ein Detail-Datensatz eingefügt werden, wenn der Wert der Fremdschlüsselspalte bereits als Primärschlüssel in der übergeordneten Master-Tabelle vorhanden ist.

          2. Es kann nur dann ein Master-Datensatz gelöscht werden, wenn vorher alle abhängigen Detaildatensätze gelöscht wurden.

          Dies führt dazu, dass auch die für die einzelnen Tabellen zuständigen TableAdapter je nach Situation in unterschiedlicher Reihenfolge ausgeführt werden müssen:


          Master-/Detail-Datensätze einfügen oder ändern: Zuerst Master-TableAdapter aufrufen, danach den Detail-TableAdapter

          Master-/Detail-Datensätze löschen: Zuerst den Detail-TableAdapter aufrufen und erst danach den Master-TableAdapter

          Die gelöschten Datensätze müssen also in einer anderen Reihenfolge eingespielt werden als alle anderen. Für die Trennung stehen 2 Wege offen:

          a) Select-Methode filtert den DataViewRowState-Wert Deleted
          b) GetChanges-Methode filtert den DataViewRowState-Wert Deleted

          Der Weg a) könnte zum Beispiel so aussehen:

          <div style="font-family: Consolas; font-size: 10pt; color: black; background: white;"><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span> <span style="color: blue;">void</span> Form1_Load(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">// Zuerst die Master-Ergebnismenge, danach erst die Detail-Ergebnismenge laden</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.verfahrenTableAdapter.Fill(<span style="color: blue;">this</span>.dataSet1.Verfahren);</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.inhaltsverzeichnisTableAdapter.Fill(<span style="color: blue;">this</span>.dataSet1.Inhaltsverzeichnis);</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p><p style="margin: 0px;">&nbsp;</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">private</span> <span style="color: blue;">void</span> verfahrenBindingNavigatorSaveItem_Click(<span style="color: blue;">object</span> sender, <span style="color: #2b91af;">EventArgs</span> e)</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; {</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.Validate();</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.verfahrenBindingSource.EndEdit();</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.inhaltsverzeichnisBindingSource.EndEdit();</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">//</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">// Phase 1: Die neu eingefügten Datensätze</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">//</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.verfahrenTableAdapter.Update(<span style="color: blue;">this</span>.dataSet1.Verfahren.Select(<span style="color: #a31515;">""</span>, <span style="color: #a31515;">""</span>, <span style="color: #2b91af;">DataViewRowState</span>.Added));</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.inhaltsverzeichnisTableAdapter.Update(<span style="color: blue;">this</span>.dataSet1.Inhaltsverzeichnis.Select(<span style="color: #a31515;">""</span>, <span style="color: #a31515;">""</span>, <span style="color: #2b91af;">DataViewRowState</span>.Added));</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">//</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">// Phase 2: Die geänderten Datensätze</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">//</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.verfahrenTableAdapter.Update(<span style="color: blue;">this</span>.dataSet1.Verfahren.Select(<span style="color: #a31515;">""</span>, <span style="color: #a31515;">""</span>, <span style="color: #2b91af;">DataViewRowState</span>.ModifiedCurrent));</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.inhaltsverzeichnisTableAdapter.Update(<span style="color: blue;">this</span>.dataSet1.Inhaltsverzeichnis.Select(<span style="color: #a31515;">""</span>, <span style="color: #a31515;">""</span>, <span style="color: #2b91af;">DataViewRowState</span>.ModifiedCurrent));</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">//</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">// Phase 3: Die gelöschten Datensätze</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: green;">//</span></p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.inhaltsverzeichnisTableAdapter.Update(<span style="color: blue;">this</span>.dataSet1.Inhaltsverzeichnis.Select(<span style="color: #a31515;">""</span>,<span style="color: #a31515;">""</span>,<span style="color: #2b91af;">DataViewRowState</span>.Deleted));</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; <span style="color: blue;">this</span>.verfahrenTableAdapter.Update(<span style="color: blue;">this</span>.dataSet1.Verfahren.Select(<span style="color: #a31515;">""</span>,<span style="color: #a31515;">""</span>,<span style="color: #2b91af;">DataViewRowState</span>.Deleted));</p><p style="margin: 0px;">&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; }</p></div>

          Da nur für die gelöschten Datensätze eine andere Reihenfolge notwendig ist, können die beiden anderen DataViewRow-State-Werte auch gemeinsam abgefragt werden: ...Select("", "", DataViewRowState.Added | DataViewRowState.Deleted));

          Comment


          • #6
            Hallo Herr Kosch,

            diese Lösungen die Sie mir gepostet haben gehen nur wenn ich mit zwei DataGridViews, eines für die Mastertabelle und eines für die Detailtabelle arbeite.

            Ich verwende aber für die Mastertabelle Labels und Textboxen und für die Detailtabelle ein DataGridView. Hier gehen die beschriebenen Wege aber nicht mehr.
            Können Sie mir noch einen Tip geben wie Ich das hin bekomen kann.

            Vielen Dank!
            Mit freundlichen Grüßen
            Klaus-Dieter Held

            Comment


            • #7
              Hallo,

              Hier gehen die beschriebenen Wege aber nicht mehr.
              was bedeutet dieser Satz genau? Für den TableAdapter spielt es doch überhaupt gar keine Rolle, ob überhaupt Controls bzw. welche Controls an eine BindingSource gebunden werden.

              Comment


              • #8
                Hallo Herr Kosch,
                momentan weiß ich selbst nicht mehr genau wo ich ansetzen muß!

                Befolge ich Ihren ersten Tip und stelle alle Angaben die Sie mir gegeben haben im DataSet ein, dann bekomme ich schon eine Schutzverletzung beim Starten des Projektes mit folgenden aussagen.

                "ConstraintExeption wurde nicht behandelt"
                "Einschränkungen konnten nicht aktiviert werden. Mindestens eine Zeile enthält Werte die die Einschränkungen non-null, unique or foreign-key verletzen."

                Stelle ich die Verbindungseinstellungen im Dataset auf "Nur Beziehungen" startet das Projekt und ich kann neue Datensätze anlegen. Wenn ich dann aber die Änderungen über die Update Methode mit folgenden Befehlen aktualisiere
                private void mITGLIEDERBindingNavigatorSaveItem_Click(object sender, EventntArgs e)
                {
                this.Validate();
                this.mITGLIEDERBindingSource.EndEdit();
                this.aKTIVEVONBISBindingSource.EndEdit();

                this.mITGLIEDERTableAdapter.Update(this.gV1883Part enheimDataSet.MITGLIEDER.Select("","",
                DataViewRowState.Added|DataViewRowState.ModifiedCu rrent));
                this.aKTIVEVONBISTableAdapter.Update(this.gV1883Pa rtenheimDataSet.AKTIVEVONBIS.Select("","",
                DataViewRowState.Added|DataViewRowState.ModifiedCu rrent));

                this.aKTIVEVONBISTableAdapter.Update(this.gV1883Pa rtenheimDataSet.AKTIVEVONBIS.Select("", "",
                DataViewRowState.Deleted));
                this.mITGLIEDERTableAdapter.Update(this.gV1883Part enheimDataSet.MITGLIEDER.Select("", "",
                DataViewRowState.Deleted));

                }
                gibt es wieder die Schutzverletzung mit folgender Aussage.
                "Die INSERT-Anweisung steht in Konflikt mit der FOREIGN KEY-Einschränkung "FK_AKTIVEVONBIS_MITGLIEDER". Der Konflikt trat in der "GV1883Partenheim"-Datenbank, Tabelle "dbo.MITGLIEDER", column 'MITGID' auf.
                Die Anweisung wurde beendet."

                Danach ist in der Tabelle Mitglieder der Datensatz vorhanden, jedoch der Detaildatensatz fehlt.

                Ich komme hier einfach nicht weider.
                Gibt es eine Möglichkeit Ihnen das Projekt und die Datenbank einmal zu senden?

                Mit freundlichen Grüßen
                Klaus Dieter Held

                Comment


                • #9
                  Hallo,

                  Stelle ich die Verbindungseinstellungen im Dataset auf "Nur Beziehungen" startet das Projekt...
                  die Ursache für dieses Problem liegt darin, dass Visual Studio 2005 die Reihenfolge der Fill-Aufrufe der TableAdapter nicht automatisch anpasst. In der Voreinstellung wird leider zuerst die Detail-Tabelle geladen und erst danach die Master-Tabelle.

                  Wenn die Datenmenge aktualisiert werden soll, darf die Verbindungseinstellungen im Dataset nicht auf "Nur Beziehungen" gestellt werden. Statt dessen muss in der Load-Ereignisbehandlung die Reihenfolge der Fill-Aufrufe von Hand so angepasst werden, dass zuerst die Master-Datenmenge gefüllt wird.

                  Comment


                  • #10
                    Hallo,

                    Danke für den Tipp mit DataViewRowState!
                    Hab bis eben lange gegoogelt und bin hier fündig geworden.

                    Funzt wunderbar, hatte davor immer versucht es über GetChanges(DataRowState) zu lösen.

                    Danke nochmals, der Thread hat mir wirklich sehr geholfen!

                    Comment

                    Working...
                    X