25.3 Den lokalen Datenspeicher füllen
Es lässt sich trefflich darüber streiten, welche Methode eines bestimmten Typs die wichtigste ist. Bei einem DataAdapter-Objekt ist das auch nicht anders, aber meiner Meinung nach sind es zwei Methoden, die den Kern dieses Typs ausmachen:
- Fill
- Update
Mit der Methode Fill wird der lokale Datenspeicher mit dem Ergebnis einer SELECT-Abfrage gefüllt. Dazu wird für die Dauer der Abfrageoperation eine Verbindung zur Datenquelle geöffnet und nach der Beendigung wieder geschlossen. Die empfangenen Daten werden in einem DataTable-Objekt vorgehalten, das sich in einem DataSet befindet. DataTable beschreibt alle Spalten, die in der SELECT-Abfrage angegeben sind. Die Spaltenbezeichner werden aus der Originaldatenbank übernommen. Der Anwender kann die Daten ändern, Datensätze löschen oder neue hinzufügen. Da währenddessen kein Kontakt zur Datenbank besteht (DataTable ist ein unverbundenes Objekt), wird die Datenbank nichts von den Änderungen im DataSet bzw. der DataTable mitbekommen.
Zu irgendeinem Zeitpunkt sollen die Änderungen natürlich in die Originaldatenquelle zurückgeschrieben werden. Dazu muss die Methode Update des DataAdapters aufgerufen werden. Der DataAdapter sorgt dann dafür, dass die Verbindung erneut aufgebaut wird und die geänderten Daten in die Originaldatenbank geschrieben werden. Ist die Aktualisierung beendet, wird die Verbindung automatisch geschlossen.
Die ersten beiden Überladungen von Fill möchte ich Ihnen näher vorstellen:
Public Function Fill(ds As DataSet) As Integer Public Function Fill(dt As DataTable) As Integer Public Function Fill(ds As DataSet, srcTable As String) As Integer Public Function Fill(startRecord As Integer, maxRecords As Integer, _ ParamArray dts As DataTable()) As Integer Public Function Fill(ds As DataSet, startRecord As Integer, _ maxRecords As Integer, srcTable As String) As Integer |
Im einfachsten Fall wird entweder ein DataTable- oder ein DataSet-Objekt übergeben. Beide Typen sind unabhängig vom .NET-Datenprovider und befinden sich im Namensraum System.Data. Ein DataTable-Objekt entspricht einer Tabelle in der Datenbank. Es hat die Spalten, die in der SELECT-Abfrage angegeben worden sind, und enthält die Datensätze, die das Ergebnis der SELECT-Abfrage bilden. Der Rückgabewert der Fill-Methode gibt an, wie viele Datenzeilen dem DataSet oder der DataTable hinzugefügt wurden.
Ein DataSet-Objekt können Sie sich als einen Container für mehrere DataTable-Objekte vorstellen. Im Beispiel weiter oben hätten wir auch anstelle eines DataTable-Objekts ein DataSet füllen können. Der Code in der Schleife muss dann entsprechend angepasst werden.
... Dim ds As DataSet = New DataSet() da.Fill(ds) For Each row As DataRow In ds.Tables(0).Rows Console.WriteLine("{0,-35} {1} ", row(0), row(1)) Next
Nach dem Füllen einer DataTable oder eines DataSets gibt es keine Verbindung mehr zum DataAdapter. Das bedeutet: Der DataAdapter hat keine Referenz auf das Objekt, das er gefüllt hat, und das gefüllte Objekt weiß nicht, von wem es gefüllt worden ist.
25.3.1 Verbindungen öffnen und schließen
Kommen wir noch einmal auf das einführende Beispiel von oben zurück. Mit
Dim da As DbDataAdapter = New SqlDataAdapter() da.SelectCommand = cmd
wird das DataAdapter-Objekt erzeugt, und mit dem Kommando cmd wird auch die Verbindung con festgelegt. Es fällt auf, dass die Open-Methode nicht aufgerufen wird, um die Abfrage zu übermitteln. Das ist auch nicht nötig, denn mit
da.Fill(tbl)
öffnet der DataAdapter die Verbindung selbstständig, fragt die Ergebnisse ab und schließt die Verbindung auch selbstständig. Das steht ganz im Gegensatz zu den Execute-Methoden des Command-Objekts, die auf das explizite Öffnen der Verbindung angewiesen sind.
Sie können allerdings explizit eine Verbindung mit Open öffnen und erst danach Fill aufrufen. Der DataAdapter wird die geöffnete Verbindung bemerken und lehnt im Weiteren auch die Verantwortung dafür ab, die Verbindung nach dem Eintreffen der Abfrageresultate zu schließen. Es liegt dann bei Ihnen, die offene Verbindung zu schließen.
... con.Open() da.Fill(tbl) con.Close()
25.3.2 Doppelter Aufruf der Fill-Methode
Angenommen, Sie rufen zweimal hintereinander die Fill-Methode auf, ohne vor dem zweiten Aufruf das DataSet oder die DataTable zu leeren, also:
... da.Fill(tbl) da.Fill(tbl)
Die Idee, die dem doppelten Aufruf zugrunde liegt, könnte die Aktualisierung des DataSets sein. Allerdings werden nun die Datensätze in der Tabelle doppelt auftreten. Mit dem ersten Aufruf der Fill-Methode wird das DataTable-Objekt erzeugt, und es werden die Datensätze hineingeschrieben, und mit dem zweiten Aufruf werden die Datensätze einfach noch einmal aus der Datenquelle bezogen und in die schon vorhandene Tabelle kopiert.
Der Grund für dieses auf den ersten Blick etwas sonderbare Verhalten ist, dass die Primärschlüsselspalte der Originaltabelle nicht zur Primärschlüsselspalte der DataTable wird. Primärschlüssel dienen unter anderem zur Vermeidung von duplizierten Datensätzen und müssen in der Datenquelle festgelegt werden. Die DataTable übernimmt diese jedoch nicht automatisch.
25.3.3 Mehrere DataAdapter-Objekte aufrufen
Wird die Methode Fill hintereinander auf verschiedene DataAdapter aufgerufen, wird jeweils eine neue Verbindung benötigt. Daran ändert sich auch nichts, wenn allen Aufrufen dieselbe Verbindungszeichenfolge zugrunde liegt.
... Dim daProducts As DbDataAdapter = New SqlDataAdapter(strSQL1, con) Dim daCategories As DbDataAdapter = New SqlDataAdapter(strSQL2, con) Dim dsProducts As DataSet = New DataSet() Dim dsCategories As DataSet = New DataSet() daProducts.Fill(dsProducts) ... daCategories.Fill(dsCategories)
Zuerst wird das DataSet namens dsProducts gefüllt. Dazu wird die Verbindung con geöffnet und nach Abschluss der Operation wieder geschlossen. Anschließend landet con im Verbindungspool. Der DataAdapter namens daCategories bedient sich der Verbindung im Verbindungspool, muss aber seinerseits die Verbindung selbst öffnen und nach dem Empfangen der Abfrageergebnisse wieder schließen. Damit sind Leistungseinbußen verbunden.
Wollen Sie sicherstellen, dass eine Verbindung von beiden DataAdapter-Objekten gleichermaßen benutzt wird, müssen Sie die Steuerung selbst übernehmen und die Verbindung mit der Open-Methode vor dem Füllen des ersten DataDets bzw. DataTable öffnen.
... con.Open() daProducts.Fill(dsProducts) daCategories.Fill(dsCategories) con.Close()
Da Sie nun der Fill-Methode die Verantwortung für die Beständigkeit der Verbindung entrissen haben, dürfen Sie am Ende nicht vergessen, die Verbindung mit Close zu schließen.
25.3.4 Der Spalten- und der Tabellenbezeichner einer DataTable
Intern bedient sich ein DataAdapter des DataReader-Objekts, um die Ergebnisse einer Abfrage abzurufen. Bevor die Resultate der Abfrage in der DataTable gespeichert werden, benutzt der DataAdapter das DataReader-Objekt, um sich elementare Schemainformationen zu besorgen. Dazu gehören die Spaltenbezeichner und die Datentypen. Aus diesem Grund können Sie über die Spaltenbezeichner auf bestimmte Spalten zugreifen, wenn Sie die Datenzeilen auswerten. Der DataReader ist jedoch nicht in der Lage, den Tabellennamen zu liefern. Standardmäßig heißt die erste Tabelle Table, die zweite Table1, die dritte Table2 usw. Sie können aber auch eine Überladung der Fill-Methode benutzen, der Sie im zweiten Parameter den Tabellennamen übergeben:
daProducts.Fill(dsProducts, "Artikel")
Nun wird die Tabelle im DataSet unter dem Namen Artikel angesprochen, nicht mehr unter Table.
25.3.5 Paging mit der Fill-Methode
Eine interessante Überladung der Fill-Methode möchte ich Ihnen noch vorstellen. Diese gestattet es, die DataTable mit nur einem Teil des Abfrageergebnisses zu füllen.
daProducts.Fill(dsProducts, 0, 10, "Artikel")
Dieser Aufruf bewirkt, dass nur die ersten zehn Datenzeilen des nullbasierten Abfrageergebnisses im DataSet gespeichert werden. Tatsächlich werden dabei aber immer noch alle Datenzeilen von der Abfrage zurückgegeben. Der DataAdapter, der sich intern des DataReaders bedient, ruft dabei aber nur zehnmal die Read-Methode des DataReaders auf.
Ihre Meinung
Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.