# 25 ADO.NET – Der SqlDataAdapter Das Command-Objekt dient der Datenabfrage. Es liefert jedoch Daten, die nicht editiert werden können, was in den meisten Fällen nicht den Anforderungen an eine Software entspricht. Damit Daten auch verändert werden können, müssen einige Voraussetzungen geschaffen werden. Eine davon liefert das DataAdpter-Objekt, mit dem wir uns in diesem Kapitel beschäftigen werden. ## 25.1 Was ist ein »DataAdapter«? Weiter oben haben Sie erfahren, wie Sie ein SQL-Kommando gegen eine Datenbank absetzen. Sie wissen, dass mit der Methode ExecuteNonQuery des SqlCommand-Objekts eine Aktionsabfrage ausgeführt werden kann und dass von ExecuteReader ein SqlDataReader-Objekt zurückgeliefert wird, in dem wir eine Datenzeile nach der anderen durchlaufen. Für ganz einfache Anforderungen mag das durchaus genügen. Für die Praxis sind die Anforderungen damit aber nicht ausreichend abgedeckt. Was ist, wenn wir es dem Anwender ermöglichen wollen, beliebig zwischen den einzelnen Datensätzen zu navigieren? Wie kann ein Anwender die eingelesenen Datensätze aktualisieren? Wie kann seitens der Anwendung sichergestellt werden, dass bei der Aktualisierung Einschränkungen (Constraints) berücksichtigt werden? Grundsätzlich ließen sich diese und viele weitere Fragen mit dem SqlCommand- und dem SqlDataReader-Objekt beantworten. Aber denken wir einen Schritt weiter. Beide Objekte sind von einer geöffneten Verbindung zur Datenbank abhängig. Wollen wir es einem Anwender ermöglichen, durch die Datensätze zu navigieren, müssten wir entweder die Verbindung zur Datenquelle für einen längeren Zeitraum geöffnet halten oder die einzelnen Datensätze lokal zwischenspeichern. Eine Verbindung länger als unbedingt notwendig geöffnet zu halten, ist aus vielerlei Hinsicht nicht akzeptabel. Stellen Sie sich beispielsweise eine Datenbank im Internet vor: Eine geöffnete Verbindung kostet Geld, und die Netzwerkressourcen werden belastet. Zudem ist die Anzahl der gleichzeitigen Zugriffe auf eine Datenbank begrenzt. Eine optimale Lösung müsste mindestens die folgende Fähigkeit haben: einlesen und zwischenspeichern aller Datensätze im lokalen Speicher. Wir brauchen diesen Ansatz jedoch nicht selbst zu programmieren, er wird uns von ADO.NET angeboten. Als Bindeglied zwischen der Datenquelle und dem lokalen Speicher dient dazu ein spezielles Objekt vom Typ SqlDataAdapter. Es hat die Fähigkeit, Daten aus einer Datenquelle abzufragen und sie in einer oder mehreren Tabellen des lokalen Speichers abzulegen. Darüber hinaus kann hat ein SqlDataAdapter-Objekt aber auch Änderungen in den Tabellen des lokalen Speichers an die Datenquelle übermitteln. Um die Netzwerk- und Datenbankbelastung so gering wie möglich zu halten, baut das SqlDataAdapter-Objekt nur dann eine Verbindung zur Datenbank auf, wenn dies notwendig ist. Sind alle Operationen beendet, wird die Verbindung wieder geschlossen. Im Zusammenhang mit einem SqlDataAdapter spielen auch SqlConnection- und SqlCommand-Objekte eine wichtige Rolle. Alle drei sind providerspezifisch und werden zu den verbundenen Typen des ADO.NET-Objektmodells gezählt. Die Daten im lokalen Speicher, die von speziellen Objekten verwaltet und organisiert werden, werden zu den unverbundenen Typen des ADO.NET-Objektmodells gerechnet. Ein SqlDataAdapter kann daher als Bindeglied zwischen den verbundenen und den unverbundenen Objekten angesehen werden. Ein SqlDataAdapter spielt in zwei Situationen eine wichtige Rolle: beim Füllen eines DataSets oder einer DataTable beim Aktualisieren der geänderten Inhalte von DataSet bzw. DataTable In diesem Kapitel werden wir uns ausschließlich mit dem Abrufen von Dateninformationen und dem sich daran anschließenden Füllen der lokalen Objekte beschäftigen. Die andere Fähigkeit des SqlDataAdapters sehen wir uns an, wenn wir das DataSet ausgiebig studiert haben. #### Ein Programmbeispiel Ehe wir uns mit dem DataAdapter-Objekt genauer beschäftigen, möchte ich Ihnen ein Beispiel vorstellen, das einen SqlDataAdapter benutzt, um den lokalen Speicher mit allen Datensätzen der Tabelle Products zu füllen. Abgefragt werden nur die Spalten ProductName und UnitPrice. Die lokale Datensatzliste wird anschließend an der Konsole ausgegeben. Dazu werden alle Datensätze in einer Schleife durchlaufen.
    // ------------------------------------------------------------------
    // Beispiel: ...\Kapitel 25\DataAdapterSample
    // ------------------------------------------------------------------
    SqlConnection con = new SqlConnection("...");
    string strSQL = "SELECT ProductName, UnitPrice FROM products";
    SqlDataAdapter da = new SqlDataAdapter(strSQL, con);
    DataTable tbl = new DataTable();
    da.Fill(tbl);
    // Anzeige der Daten im lokalen Speicher
    for (int i = 0; i < tbl.Rows.Count; i++) {
      DataRow row = tbl.Rows[i];
      Console.WriteLine("{0,-35} {1} ", row[0], row[1]);
    }