none
Wie arbeitet ein "System.Data.SqlClient.SqlDataAdapter" (Insert/Update/Delete) genau? RRS feed

  • Frage

  • Hallo Community,

    ich benötige einen schlauen Rat. Ich baue mir zu Übungszwecken ein eigenes DAO, das mir Daten aus einer MSSQL Datenbank (in diesem Fall 2008 R2) liefert. Nun möchte ich wissen, wie so ein "normaler" SqlDataAdapter arbeitet.

    Ich habe mir 2 Methoden ausgedacht, wie so ein DataAdapter arbeiten kann.

    1. Er erstellt für jede (sagen wir mal DataRow) einen Insert/Update/Delete Command einen SqlCommandText und ersetzt die SqlParameterNamen durch die Variablen und führt diesen aus.

    2. Noch habe ich mir vorgestellt, dass dieser den einfachen SqlCommandText zum Server schickt und die Parametervariablen im Nachhinein einfach (pro DataRow) ändert und dann ausführt.

    Beim ersten Gedanken kann ich mir vorstellen, wie dieser funktioniert, aber wie soll der zweite Gedanke lösbar sein? Ich bin mir aber auch irgendwie ziemlich sicher, dass der zweite Gedanke der richtige ist, da ich (soweit ich mich richtig erinnern kann) in der Datenbanküberwachung die SqlCommandTexte in dieser Form gesehen habe.

    Würde mich freuen, wenn jemand eine Antwort parat hat :)

    MFG Benutzer0000

    Dienstag, 17. Februar 2015 14:45

Antworten

  • Hallo,

    um die Verwendung zu verstehen, muss Du Dich mit der Funktionsweise einer DataTable auseinandersetzen. Die DataRow einer DataTable verwaltet  mehrere Zustände die über die DataRowVersion angesprochen werden können.

    Für einen Update Befehl z. B. benötigt man zum einen die aktuellen Werte, zum anderen die Originalwerte, um zu erkennen, welche Spalten überhaupt verändert wurden und um die richtige Zeile zu verändern - ein Primärschlüssel ist üblicherweise unveränderlich, muss aber nicht.

    Bei Insert gibt es nur neue, bei Delete interessieren wiederum die Originalwerte. Welche Daten man auswertet hängt davon ab, welche Parallelitätsoption man erreichen möchte.

    Mit Hilfe der ParameterDirection kann man auch Daten aus einem Befehl abrufen, was z. B. bei gespeicherten Prozeduren verwendet werden kann. Das geht u. a. mit der UpdatedRowSource Eigenschaft des SqlCommand zusammen.

    Die Precision Eigenschaft gibt die Genauigkeit bei (SQL) Decimal Datentypen an, die Scale Eigenschaft die Dezimalstellen  - was u. U. aus der Datenbank ermittelt werden muss, da der .NET Decimal Datentyp keine Restriktionen kennt (er hat einfach 28 Stellen).

    Ein DbDataAdapter.Update durchläuft alle Zeilen der DataTable, identifiziert anhand des RowState den auszuführenden Befehl und weist den Parametern anhand der Informationen die Daten zu.

    Am Ende kann man ExecuteNonQuery verwenden, wenn man keine Rückgaben erwartet. Meist wird man ExecuteReader verwenden, da der SQL Server die Rückgabe von Daten ermöglicht; zum Abrufen von Identitätswerten, aber auch von weiteren Spalten, die z. B. durch Trigger geändert wurden - siehe dazu die OUTPUT Klausel.

    Gruß Elmar

    • Als Antwort markiert Benutzer0000 Mittwoch, 18. Februar 2015 16:29
    Mittwoch, 18. Februar 2015 13:44
    Beantworter
  • Hi,
    ParameterDirection zeigt die Richtung des Wertetransfers an. In einer SP können Output-Parameter genutzt werden, die nach der Ausführung der Anweisung abgerufen werden können.

    Mit der DataRowVersion kann die Version des DataRow-Objektes festgelegt werden, aus welcher die Werte gezogen werden. Es ist wichtig, die beiden Eigenschaften eines DataRow-Objektes "DataRowVersion" und DataRowState" im Zusammenhang mit AcceptChanges und RejectChanges zu verstehen.

    Nach AcceptChanges hat ein DataRow-Objekt den RowState=Unchanged und es gibt nur eine Version=Original. Nach Änderungen ist der RowState=Modified und es gibt eine weitere Version=Current. Neue DataRow-Objekte haben, solange sie sich noch nicht in der Rows-Auflistung befinden, haben eine RowState=Added und nur eine Version=Current. Usw.

    --
    Peter

     
    Mittwoch, 18. Februar 2015 13:54

Alle Antworten

  • Hi,
    Variante 1 bedeutet, dass die Inhalte der Zeile in die SQL Anweisung durch Verkettung integriert werden. Damit wird SQL Injection ermöglicht, was ein hohes Sicherheitsrisiko sein kann.

    Variante 2 ist die typische und sichere Lösung, entweder mit Parametern in der SQL Anweisung zu arbeiten oder mit Stored Precedures.

    --
    Peter

    Dienstag, 17. Februar 2015 15:43
  • Hallo,

    schau Dir mal den (umfangreichsten) Konstruktor von SqlParameter an. Der erlaubt die Mitgabe aller notwendigen Informationen und wird auch vom SqlCommandBuilder verwendet, wenn er dynamisch Befehle generiert. Die DbCommandBuilder Klasse (respektive SqlCommandBuilder) kennt weitere Methoden, wie man Bezeichner sicher bilden kann (QuoteIdentifier).

    Damit ist Gedanke 2. umsetzbar - Gedanke 1. vergiss am besten gleich wieder (siehe Peters Antwort), auch wenn man es mit größerem Aufwand machen kann. Generell sind parametrisierte Befehle nicht nur sicherer, sondern auch schneller, da sie den Aufwand des Übersetzens (Erstellen eines Ausführungsplans) auf SQL Server Seite vermindern.

    Gruß Elmar


    Dienstag, 17. Februar 2015 19:19
    Beantworter
  • Hallo,

    ich bin jetzt soweit, das ich den SqlParameter Konstruktor fast komplett verstehe.

    In den Punkten in denen ich mir noch nicht sicher bin sind:
    • ParameterDirection
    • DataRowVersion
    • Precision
    • Scale

    ParameterDirection gibt so ich ich verstehe die Richtung des Commands an? Möchte ich Speichern oder Laden?

    DataRowVersion verstehe ich überhaupt nicht. Es gibt die Auswahl Current/Ordinal/Default/Proposed und wann welcher Wert verwendet werden soll verstehe ich überhaupt nicht.

    Precision und Scale soll soweit ich weiß für Datentypen sein, wie Decimal

    So, BTT:

    Es läuft also so, das der SqlDataAdapter jeden Datensatz durchläuft und jedesmal den Value vom SqlParameter setzt.

    Danach führt er ein SqlCommand.ExecuteNonQuery() / SqlCommand.ExecuteScalar() aus oder liege ich da falsch? :o

    MFG Benutzer0000

    Mittwoch, 18. Februar 2015 13:08
  • Hallo,

    um die Verwendung zu verstehen, muss Du Dich mit der Funktionsweise einer DataTable auseinandersetzen. Die DataRow einer DataTable verwaltet  mehrere Zustände die über die DataRowVersion angesprochen werden können.

    Für einen Update Befehl z. B. benötigt man zum einen die aktuellen Werte, zum anderen die Originalwerte, um zu erkennen, welche Spalten überhaupt verändert wurden und um die richtige Zeile zu verändern - ein Primärschlüssel ist üblicherweise unveränderlich, muss aber nicht.

    Bei Insert gibt es nur neue, bei Delete interessieren wiederum die Originalwerte. Welche Daten man auswertet hängt davon ab, welche Parallelitätsoption man erreichen möchte.

    Mit Hilfe der ParameterDirection kann man auch Daten aus einem Befehl abrufen, was z. B. bei gespeicherten Prozeduren verwendet werden kann. Das geht u. a. mit der UpdatedRowSource Eigenschaft des SqlCommand zusammen.

    Die Precision Eigenschaft gibt die Genauigkeit bei (SQL) Decimal Datentypen an, die Scale Eigenschaft die Dezimalstellen  - was u. U. aus der Datenbank ermittelt werden muss, da der .NET Decimal Datentyp keine Restriktionen kennt (er hat einfach 28 Stellen).

    Ein DbDataAdapter.Update durchläuft alle Zeilen der DataTable, identifiziert anhand des RowState den auszuführenden Befehl und weist den Parametern anhand der Informationen die Daten zu.

    Am Ende kann man ExecuteNonQuery verwenden, wenn man keine Rückgaben erwartet. Meist wird man ExecuteReader verwenden, da der SQL Server die Rückgabe von Daten ermöglicht; zum Abrufen von Identitätswerten, aber auch von weiteren Spalten, die z. B. durch Trigger geändert wurden - siehe dazu die OUTPUT Klausel.

    Gruß Elmar

    • Als Antwort markiert Benutzer0000 Mittwoch, 18. Februar 2015 16:29
    Mittwoch, 18. Februar 2015 13:44
    Beantworter
  • Hi,
    ParameterDirection zeigt die Richtung des Wertetransfers an. In einer SP können Output-Parameter genutzt werden, die nach der Ausführung der Anweisung abgerufen werden können.

    Mit der DataRowVersion kann die Version des DataRow-Objektes festgelegt werden, aus welcher die Werte gezogen werden. Es ist wichtig, die beiden Eigenschaften eines DataRow-Objektes "DataRowVersion" und DataRowState" im Zusammenhang mit AcceptChanges und RejectChanges zu verstehen.

    Nach AcceptChanges hat ein DataRow-Objekt den RowState=Unchanged und es gibt nur eine Version=Original. Nach Änderungen ist der RowState=Modified und es gibt eine weitere Version=Current. Neue DataRow-Objekte haben, solange sie sich noch nicht in der Rows-Auflistung befinden, haben eine RowState=Added und nur eine Version=Current. Usw.

    --
    Peter

     
    Mittwoch, 18. Februar 2015 13:54
  • Hallo,

    Ich bedanke mich bei euch beiden, Ihr habt mir sehr geholfen.

    MFG Benutzer0000

    Mittwoch, 18. Februar 2015 16:29