Know-how Einführung in ADO.NET Einführung in ADO.NET Manfred Hoffbauer, Düsseldorf Die in Microsoft Access integrierte Programmiersprache VBA unterstützt den Zugriff auf AccessDatenbanken per DAO und ADO. Auch in Microsoft Visual Basic.NET ist mit ADO.NET eine Technik für den Zugriff auf solche Datenbanken enthalten. Der folgende Beitrag beschreibt die wichtigsten Techniken für den lesenden und schreibenden Inhalt 1 2 3 4 Achtung: Theorie! ............................................. 1 Von DAO über ADO zu ADO.NET .................. 1 Datenabfrage mit den OleDB-Objekten..... 3 Verbindungslose Datenzugriffsarchitektur................................ 6 5 Zusammenfassung und Ausblick................11 Zugriff auf die Daten einer Access-Datenbank. 1 2 Achtung: Theorie! Einer der Gründe für den Erfolg von Access ist, dass man auch mit wenigen Kenntnissen schnell achtbare Ergebnisse erzielt und alle notwendigen Hilfsmittel in einer einzigen Anwendung findet. Für die Erstellung einer Anwendung auf Basis der .NET-Technologien bedarf es weit mehr: Dazu sind Kenntnisse in Winforms oder ASP.NET, ADO.NET und einer .NET-Programmiersprache wie C#.NET oder VB.NET erforderlich. Da der vorliegende Beitrag aber „nur“ eine Einführung in ADO.NET geben möchte, sind die Beispiele auf das Mindeste reduziert – sie haben keine Benutzeroberfläche und auch die Ausgabe der Ergebnisse erfolgt lediglich per Konsole. Alles andere hätte auch den Rahmen gesprengt und zu sehr vom eigentlichen Thema abgelenkt. Dafür lernen Sie aber alle wichtigen Techniken für den Zugriff auf eine Access-Datenbank per ADO.NET kennen und können diese Kenntnisse später leicht aufgreifen, wenn Sie einmal eine „richtige“ .NET-Anwendung mit Benutzeroberfläche erstellen. Hinweis Die Beispieldaten befinden sich auf der Heft-CD in der Zip-Datei ADO.NET.zip. Als Beispieldatenbank dient die Adressverwaltung, die Sie unter dem Dateinamen Adress97.mdb bzw. Adress00.mdb auf der Heft-CD finden. Den kompletten Code mit allen Beispielen enthält die Datei Main.vb. computer.haufe.de Von DAO über ADO zu ADO.NET Schon seit mehreren Jahren beherrscht Access neben DAO ein weiteres Verfahren für den Datenzugriff. Mit den so genannten Active Data Objects (kurz: ADO) verfügt der AccessProgrammierer über ein modernes Verfahren für den Datenzugriff. Zahlreiche Beiträge von Access im Unternehmen haben sich mit den Vor- und Nachteilen von ADO und DAO beschäftigt. Einer der wichtigsten Vorteile von ADO besteht wohl darin, dass Sie mit dieser Technik sowohl auf Access-Datenbanken als auch auf SQL ServerDatenbanken zugreifen können. Microsoft selbst weist immer wieder darauf hin, dass DAO und ADO bei der Programmierung mit Access ihre Berechtigung haben. Je nach Anwendung ist die eine oder die andere Zugriffstechnik besser geeignet. 2.1 ADO.NET Die mit .NET eingeführte Methode für den Datenzugriff nennt Microsoft ADO.NET. Wie der Name schon verrät, hat ADO.NET mehr Ähnlichkeiten mit ADO als mit DAO. Access-Programmierer, die bisher vorwiegend mit DAO gearbeitet haben, müssen sich also umstellen. Wie bei ADO basiert bei ADO.NET der gesamte Datenzugriff auf einem Connection-Objekt. Mit ihm öffnen Sie unter Verwendung eines .NETDatenproviders den Zugang zu einer Datenquelle. Abb. 1 zeigt eine Übersicht über die Datenzugriffsobjekte. Access, SQL & .NET PREVIEW 1 Know-how Einführung in ADO.NET Hinweis Im Zusammenhang mit ADO.NET ist von Objekten wie Connection, DataCommand und DataAdapter die Rede. Tatsächlich sind diese Objekte in Microsoft.NET gar nicht vorhanden. Es handelt sich lediglich um Oberbegriffe für die je nach verwendeter Technik dedizierten Objekte. Bei Verwendung von OleDB verwenden Sie die Objekte OleDBConnection, OleDbCommand und OleDBDataAdapter. Diese Objekte befinden sich im Namespace System.Data.OleDB. 2.2 Der OleDbConnection-String Die Anforderungen an den ConnectionString variieren stark zwischen SqlClient, OleDB und ODBC. Speziell beim OleDBConnection-String können Sie innerhalb des Strings einen Datenprovider spezifizieren. Mögliche Einträge lauten wie folgt: • SQLOLEDB: SQL Server ab Version 6.5 • MSDAORA: Oracle-Datenbanken Im Namespace System.Data.SqlClient ist der Datenprovider für SQL Server-Datenbanken (ab Version 7.0) enthalten. Im Namespace System.Data.OleDB ist der Datenprovider für andere Datenquellen enthalten. Seit der Version 1.1 des Microsoft .NETFrameworks befinden sich im Namespace System.Data.ODBC die Objekte für den Zugriff mit der ältesten der drei Techniken. Bei Version 1.0 des .NET-Frameworks musste der ODBC-Provider nachträglich installiert werden. • Microsoft.Jet.OLEDB.4.0: Microsoft JET, also MDB-Datenbankdateien von Microsoft Access 2.3 Combine anlegen Um die Beispiele aus diesem Beitrag nachzuvollziehen, sollten Sie mit SharpDevelop (Beschreibung und Download siehe Ausgabe 4/2004, Beitrag .Net-Programmierung mit SharpDevelop) eine neue Combine anlegen. Starten Sie das Programm und gehen Sie wie folgt vor: step by step 1 Klicken Sie im Startdialog von SharpDevelop auf den Button Neues Combine. 2 Markieren Sie die Kategorie VB.NET. 3 Markieren Sie die Schablone Konsolenanwendung. 4 Geben Sie Ado.Jet als Dateinamen ein. 5 Klicken Sie auf den Button Erstellen. Abb. 1: Datenzugriffsobjekte 2 Access, SQL & .NET PREVIEW SharpDevelop erstellt die Combine und fügt den Standardcode für eine Konsolenanwendung ein. Durch das Betäti- computer.haufe.de Know-how Einführung in ADO.NET gen der F5-Taste können Sie das Programm sofort starten. Hinweis Wenn Sie die nachfolgenden Beispiele einfach nur nachvollziehen und nicht selbst eingeben möchten, können Sie nach dem Öffnen von SharpDevelop auch direkt auf die Schaltfläche Combine öffnen klicken und die im Ordner Ado.Jet (Sharp Develop) enthaltene Datei Ado.Jet.cmbx auswählen. Die Prozedur Main enthält alle nachfolgend beschriebenen Beispiele; nach dem Betätigen von F5 durchläuft die Prozedur nacheinander die Beispiele. Wie Sie in Abb. 2 erkennen können, führt Windows die Konsolenanwendung im Fenster des Befehlszeileninterpreters aus. Durch das Betätigen einer beliebigen Taste können Sie die Anwendung beenden, was wiederum zum automatischen Schließen des Befehlszeileninterpreterfensters führt. Dieser Typ Anwendung eignet sich gut, um Techniken wie beispielsweise den Datenzugriff unabhängig von irgendwelchen Fragen der Benutzeroberfläche zu testen. 3 Datenabfrage mit den OleDB-Objekten Dieser Beitrag beschäftigt sich mit dem Zugriff auf Access-Datenbanken. Er geht deshalb vorwiegend auf OleDB und den Zugriff auf AccessDatenbanken ein. Die hierfür benötigten Objekte befinden sich im Namespace System.Data.OleDB. Um auf ein Objekt aus diesem Namespace zuzugreifen, können Sie ihm die Bezeichnung des Namespaces voranstellen oder Sie schreiben einmal zu Beginn Ihres Programms die folgende Anweisung: Imports System.Data.OleDb Dim cnnString As String cnnString = "Provider=Microsoft.Jet.OLEDB.4.0;" & _ Mit der Imports-Anweisung sparen Sie viel Schreibarbeit. Jetzt können Sie nämlich statt "Data Source=<Dateipfad>\Adress00.mdb" Dim cnn As System.Data. Dim cnn As OleDbConnection OleDb.OleDbConnection cnn = New OleDbConnection(cnnString) cnn.Open() Quellcode 1 (ohne Zeilenumbruch) vereinfacht Folgendes schreiben: Dim cnn As OleDbConnection Hierfür benötigen Sie eine Verbindung, die Sie wie in Quellcode 1 erzeugen und öffnen können. Mit der Dim-Anweisung definieren Sie die String-Variable cnnString. Abb. 2: Die von SharpDevelop generierte Konsolenanwendung können Sie sofort starten. computer.haufe.de Dieser Variablen weisen Sie den eigentlichen ConnectionString zu. Er hat die gleiche Bedeutung wie bei der Programmierung mit dem herkömmlichen ADO. Access, SQL & .NET PREVIEW 3 Know-how Einführung in ADO.NET Im Beispiel benennt er den zu verwendenden Datenprovider und die zu öffnende Access-MDBDatei. Die zweite Dim-Anweisung definiert ein neues OleDbConnection-Objekt und weist ihm die Verbindung zu. Mit cnn.Open() wird die Verbindung geöffnet. Hinweis Wenn Sie statt auf einen OleDB-Provider auf einen SQL-Provider zugreifen wollen, dann verwenden Sie statt des OleDBConnection- ein SqlConnection-Objekt. Beide Begriffe werden in der Fachliteratur als DataConnection zusammengefasst. Objekte können aber nur den Typ OleDBConnection oder SqlConnection und nicht den Type DataConnection haben. 3.1 Update-, Delete- und InsertAnweisungen per OleDbCommandObjekt ausführen Eine Connection an sich ist keine wirkliche Errungenschaft, aber die notwendige Voraussetzung für weitere Verfahren des Datenzugriffs. Basierend auf einer OleDBConnection können Sie ein OleDBCommand-Objekt definieren. Das OleDBCommand-Objekt verfügt über die drei folgenden Methoden: • ExecuteNonQuery: Mit dieser Anweisung können Sie SQL-Anweisungen ausführen, die keine Rückgabewerte haben. Beispiele sind INSERT, UPDATE und DELETE. Die Methode gibt die Anzahl der betroffenen Datensätze zurück. • ExecuteScalar: Mit dieser Methode können Sie SQL-Anweisungen ausführen, die einen einzelnen Rückgabewert erfordern (zum Beispiel die Anzahl der betroffenen Datensätze). • ExecuteReader: Mit dieser Methode erhalten Sie ein DataReader-Objekt mit dem Ergebnis Ihrer Abfrage. Damit können Sie etwa die per SELECT-Anweisung ermittelten Datensätze lesen. Die ExecuteNonQuery-Methode ist zur Ausführung von INSERT-, UPDATE- und DELETEAnweisungen geeignet. Sie ähnelt der Execute- Sub Main() Dim cnnString As String cnnString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=C:\Nordwind.mdb" Dim cnn As OleDbConnection cnn = New OleDbConnection(cnnString) cnn.Open() Dim cmdUDI As OleDbCommand cmdUDI = New OleDbCommand("UPDATE Personal SET Vorname = 'Hans' " _ & "WHERE Vorname = 'Andrew'", cnn) console.writeline("Anzahl geänderter Datensätze: " + _ cmdUDI.ExecuteNonQuery().ToString) cmdUDI = New OleDbCommand("INSERT INTO Personal ( Vorname, Nachname ) VALUES " _ & "('Manfred', 'Hoffbauer' )", cnn) console.writeline("Anzahl hinzugefügter Datensätze: " + cmdUDI.ExecuteNonQuery() cmdUDI = New OleDbCommand("DELETE FROM Personal WHERE Vorname = 'Manfred' " _ & "AND Nachname = 'Hoffbauer'", cnn) Console.WriteLine("Anzahl Deletes: " + cmdUDI.ExecuteNonQuery().ToString) cmdUDI = New OleDbCommand("SELECT COUNT(*) FROM Personal", cnn) Console.WriteLine("Anzahl Mitarbeiter: " + cmdUDI.ExecuteScalar().ToString) cnn.Close End Sub Quellcode 2 4 Access, SQL & .NET PREVIEW computer.haufe.de Know-how Einführung in ADO.NET Methode von Access. Die Anzahl der von einer Aktion betroffenen Datensätze erhalten Sie als Funktionsargument zurück. Betrachten Sie dazu die Routine aus Quellcode 2. Die Dim-Anweisung definiert das Objekt cmdUDI mit dem Typ OleDBCommand. Die anschließende Zuweisung weist dem Objekt ein neues Command-Objekt mit der jeweils angegebenen SQLAnweisung zu. Die Angabe der Verbindung bestimmt, auf welcher Datenbank die SQL-Anweisung ausgeführt wird. Die Methode cmdUDI.ExectureNonQuery() führt die SQL-Anweisung aus. Bei allen Aktionsabfragen wird die Anzahl der betroffenen Datensätze per Console.WriteLine() angezeigt. Die Methode cmdUDI.ExecuteScalar() führt die SELECT-Anweisung aus und gibt den Wert der ersten Spalte der ersten Zeile des Abfrageergebnisses als Wert zurück. Im Beispiel entspricht dies der Anzahl der Datensätze aus der Tabelle Personal. exklusiv. Das Beispiel aus Quellcode 3 zeigt das satzweise Lesen von Adressen mit dem DataReader-Objekt. Sie können eine Objektvariable vom Typ DataReader nicht direkt mit New instanzieren. Ein DataReader-Objekt kann nur mittels der ExecuteReader-Methode eines OleDBCommandObjektes erzeugt werden. Im Beispiel wird eine SELECT-Abfrage auf die Adresstabelle durchgeführt. Die Read-Methode des DataReader-Objektes gibt den Wert True zurück, wenn ein Datensatz gelesen werden konnte. Andernfalls gibt die Methode den Wert False zurück. Mit dem DataReader-Objekt können Sie unter Angabe des Feldnamens direkt auf die einzelnen Spaltenwerte zugreifen. Abb. 3 zeigt exemplarisch die Anzeige der Vornamen aus der Adressentabelle. 3.2 Daten per SELECT-Anweisung lesen Mit der ExecuteReader-Methode können Sie ein DataReader-Objekt erzeugen lassen. Mit dem DataReader-Objekt können Sie die Daten einer Abfrage vorwärts gerichtet lesen. Das Verhalten des Objekts entspricht daher ein wenig dem sequenziellen Lesen von Daten aus einer Textdatei. Das DataReader-Objekt hält immer nur einen Datensatz im Speicher und spart deshalb Ressourcen. Gleichzeitig benötigt es die Verbindung aber während seiner gesamten Lebensdauer Abb. 3: Ausgabe der Vornamen mittels DataReader-Objekt Dim strSQL As String strSQL = "SELECT Vorname, Nachname, Strasse, " _ & "PLZ, Ort FROM tblAdressen;" Dim cmd As OleDbCommand Die obige Schleife zeigt alle Vornamen aus der Adressentabelle an. Zum Schluss des Beispielprogramms sollten Sie die verwendeten Ressourcen freigeben: cmd = New OleDbCommand(strSQL, cnn) reader.Close() Dim reader As OleDbDataReader reader = cmd.ExecuteReader() cnn.Close() Console.ReadLine() While reader.Read() Console.WriteLine(reader("Vorname")) End While Quellcode 3 computer.haufe.de Die Anweisung Console.ReadLine() wartet auf eine Benutzereingabe. Sie hält das Win- Access, SQL & .NET PREVIEW 5 Know-how Einführung in ADO.NET dows-Befehlszeilenfenster so lange offen, bis Sie die Eingabetaste betätigen. 4 Verbindungslose Datenzugriffsarchitektur Der Datenzugriff mit ADO.NET basiert auf der verbindungslosen Datenzugriffstruktur. Anders als bei Microsoft Access üblich werden ein oder mehrere Datensätze aus einer oder mehreren Tabellen in den Speicher gelesen, dort bearbeitet und bei Bedarf die Änderungen geschrieben. Verbindungslos bedeutet in diesem Fall, dass nach dem Lesen der Bezug zur Datenquelle vollständig verloren gehen kann. Zur Handhabung dieser Architektur stellt ADO.NET das DataTableund das DataSet-Objekt zur Verfügung. Ein DataTable-Objekt besteht aus Zeilen und Spalten und ist prinzipiell mit einer Datentabelle vergleichbar. Ein DataSet-Objekt kann aus ein oder mehreren Tabellen und Relationen bestehen. Ein DataSet ist einerseits mit einer Datenbank vergleichbar, weist aber gleichzeitig gravierende Unterschiede auf. Dadurch bedingt, dass ein DataSet verbindungslos im Speicher gehalten wird, können die Daten der enthaltenen Tabellen aus sehr verschiedenen Quellen stammen. So lassen sich in ein und demselben DataSet Datentabellen aus einer Textdatei, einer Access-Datenbank, einer SQL-Server-Datenbank und aus weiteren Datenquellen zusammenfügen. 4.1 Daten in ein DataTable lesen Das DataAdapter-Objekt ist der Vermittler zwischen einem Connection-Objekt und einer DataTable oder einem DataSet. Es enthält die SQLAbfragen, mit denen Sie Daten lesen und schreiben. Das Beispiel aus Quellcode 4 zeigt, wie Sie die Vornamen aus der Adressentabelle mit Hilfe eines DataTable-Objektes anzeigen können. Die Dim-Anweisung definiert das Objekt tblAdressen vom Typ DataTable. Der Variablen wird gleichzeitig eine neue, leere Instanz des Objekts zugewiesen. Die zweite Anweisung definiert ein OleDBDataAdapter-Objekt, das als Vermittler zwischen der Connection und der DataTable fungiert. Bei der Definition des OleDBDataAdapter-Objekts werden eine SELECT-Anweisung und eine Connection angegeben. Mit adp.Fill(tblAdressen) werden die Daten aus der Adressentabelle in das DataTable-Objekt tblAdressen übertragen. Beachten Sie, dass der Name des DataTable-Objekts frei gewählt werden kann. Im Beispiel wurde es nur deshalb tblAdressen genannt, damit der Bezug zur Quelltabelle sofort klar wird. Alternativ könnten Sie das Objekt auch tblX oder einfach nur Adressen nennen. Dim tblAdressen As New DataTable Dim adp As New OleDbDataAdapter("SELECT * FROM tblAdressen", cnn) adp.Fill(tblAdressen) Dim row As DataRow Mit der Fill-Anweisung werden nicht nur die Daten, sondern es wird auch die Struktur in das DataTable-Objekt übertragen. For Each row In tblAdressen.Rows Console.WriteLine(row.Item("Vorname")) Next Quellcode 4 Dim col As DataColumn For Each col In tblAdressen.Columns Console.WriteLine(col.ColumnName.ToString + "->" + col.DataType.ToString) Next Quellcode 5 6 Access, SQL & .NET PREVIEW Das Objekt enthält nach der Zuweisung die gleichen Spalten inklusive Feldnamen, Datentypen und die gleiche Primärschlüsseldefinition wie die Herkunftstabelle. Die Definition der Spalten können Sie mit der Schleife aus Quellcode 5 überprüfen. Die Schleife durchläuft die Columns-Auflistung des computer.haufe.de Know-how Einführung in ADO.NET tblAdressen-Objekts. Zu jeder Spalte werden der Name und der von .NET zugewiesene Datentyp angezeigt. Das Ergebnis eines Schleifendurchlaufs sehen Sie in Abb. 4. der Rows-Auflistung können Sie die Zeilen durchlaufen und direkt auf die einzelnen Feldwerte zugreifen. Im obigen Beispiel wird exemplarisch der Wert des Feldes Vorname angezeigt. Der Auflistung in der Abbildung können Sie entnehmen, wie .NET die in der Access-Tabelle definierten Datentypen in eigene Datentypen umsetzt. Zusätzlich zu der Struktur hat die FillMethode auch alle Daten in das DataTableObjekt übernommen. Die einzelnen Datensätze stellen die Zeilen innerhalb des Objekts dar. Mit 4.2 Daten aktualisieren Das Aktualisieren der Daten in einem DataTableObjekt erfolgt durch direkte Zuweisung. Mit der folgenden Anweisung können Sie beispielsweise den Wert im Feld Vorname des vierten Datensatzes ändern (ohne Zeilenumbruch): tblAdressen.Rows(3).Item(" Vorname") = "<Unbekannt>" Beachten Sie dabei, dass die meisten Indizes in .NET auf 0 basieren. Die erste Zeile erhalten Sie mit Row(0), die zweite mit Row(1) und so weiter. Abb. 4: Diese Feldnamen und Datentypen verwendet .NET zur Verwaltung der Adressentabelle. Was nutzt das Ändern von Daten in einem verbindungslosen DataTable-Objekt? Es hat tatsächlich zunächst keinerlei Auswirkung auf den zugrunde liegenden Datenbestand. Sie können dies leicht prüfen, indem Sie einige Feldwerte ändern und dann die folgenden beiden Anweisungen in das Programm aufnehmen (ohne Zeilenumbruch): Console.WriteLine("<Bitte betätigen Sie die <Enter>Taste.") Console.ReadLine() Abb. 5: Diesen Fehler meldet ADO.NET, falls die zugrunde liegende Datenbank exklusiv gesperrt wurde. computer.haufe.de Wenn Sie das Programm zum Betätigen der Eingabetaste auffordert, können Sie die MDB-Datei öffnen und sich die Daten ansehen. Sie werden feststellen, dass keine Änderungen an den Daten durchgeführt wurden. Sie können die Access, SQL & .NET PREVIEW 7 Know-how Einführung in ADO.NET Datenbank zu diesem Zeitpunkt sogar exklusiv mit Microsoft Access öffnen. Dies ist gleichzeitig der Beweis dafür, dass die Verbindung vom DataTable-Objekt zur Datenbank vollständig gelöst wurde. Um die Daten in der zugrunde liegenden Datenbank zu aktualisieren, haben Sie prinzipiell zwei Möglichkeiten. Sie können die Rows-Auflistung des DataTableObjekts dazu verwenden, für jede geänderte Zeile eine Update-Anweisung zusammenzusetzen und diese per OleDBCommand-Objekt auszuführen. Ob eine Zeile geändert wurde, können Sie mit der RowState-Eigenschaft abfragen: die SQL-Anweisungen in der anschließenden Update-Anweisung verwendet werden. Sie schreibt die Änderungen in die zugrunde liegende Datentabelle. Zu diesem Zeitpunkt stellt .NET die Verbindung zur Datenbank wieder her und versucht, die erforderlichen UPDATE-Anweisungen durchzuführen. Falls die Access-Datenbank nicht verfügbar oder exklusiv gesperrt wurde, tritt hierbei ein Fehler auf. In Abb. 5 sehen Sie, dass sich mit der Fehlermeldung nicht allzu viel anfangen lässt. If row.RowState=DataRowState.Modified Then Dim cb As OleDbCommandBuilder = _ New OleDbCommandBuilder(adp) ... Try Die weitaus komfortablere Methode besteht darin, die beschriebenen Arbeitsschritte dem DataAdapter-Objekt zu überlassen. Dies ist ein klassischer Zweizeiler: Dim cb As OleDbCommandBuilder = New _ OleDbCommandBuilder(adp) adp.Update(tblAdressen) Mit der ersten Anweisung definieren Sie ein OleDBCommandBuilder-Objekt. Durch die Zuweisung mit New OleDBCommandBuilder(adp) veranlassen Sie .NET, dem OleDBCommandBuilder-Objekt automatisch eine UPDATE-, eine INSERT- und eine DELETE-Anweisung hinzuzufügen. Da das OleDBCommandBuilder-Objekt im DataAdapter-Objekt enthalten ist, können adp.Update(tblAdressen) Catch exOle As OleDbException Console.WriteLine(exOle.ToString) Catch ex As Exception Console.WriteLine(ex.Message) End Try Quellcode 6 Es ist deshalb empfehlenswert, die UpdateAnweisung in einen Try-Catch-Block zu schachteln (s. Quellcode 6). Mit diesen Programmzeilen erhalten Sie zwar noch keine wirkliche Fehlerbehandlung, Sie erreichen aber immerhin die Anzeige der Fehlermeldung im Klartext. Wenn Sie das Programm nun erneut starten und die AccessDatenbank vor der Ausführung der Update-Anweisung exklusiv sperren, dann erhalten Sie die Anzeige in Abb. 6. Abb. 6: Mit einem Try-Catch-Block erhalten Sie die Fehlermeldung im Klartext. 8 Access, SQL & .NET PREVIEW Die oben beschriebene Vorgehensweise basiert auf einem automatisch generierten UPDATE-Statement. Mit wenigen Programmzeilen können Sie computer.haufe.de Know-how Einführung in ADO.NET 4.3 Daten filtern Ein wichtiger Aspekt beim Abruf von Daten ist die Selektion der benötigten Datensätze. Im Hinblick auf die verwendeten Ressourcen ist es am günstigsten, die Daten direkt bei der Abfrage zu filtern. Hierzu können Sie das SQL-Statement des DataAdapter-Objekts mit einer WHERE-Klausel ausstatten (s. Quellcode 8). Abb. 7: SQL-Text eines UPDATE-Statements den SQL-Text dieses Statements in die Datei C:\Test.TXT exportieren lassen (s. Quellcode 7). Als Ergebnis erhalten Sie die UPDATE-Anweisung aus Abb. 7. In diesem Beispiel selektieren Sie spalten- und zeilenweise. Das Abfrageergebnis enthält nur den Vor- und den Nachnamen der Adressen aus dem Postleitzahlengebiet 4. .NET führt diese Anweisung für jede Zeile mit geänderten Daten einmal aus. Die Fragezeichen werden dabei durch die Werte der gleichnamigen Felder aus dem DataTable-Objekt ersetzt. Dieses Verfahren hat den Nachteil, dass das Filterkriterium statisch in den SQL-String integriert ist. Wesentlich flexibler ist die Variante, das Filterkriterium als Parameter zu definieren (s. Quellcode 9). Das OleDBCommandBuilder-Objekt enthält ähnliche Anweisungen für die DELETE- und die INSERT-Anweisung. Die Verwendung eines benannten Parameters hat den Vorteil, dass Ihre SQL-Statements besser lesbar sind. Insbesondere bei komplizierten SQL- Dim w As New System.IO.StreamWriter("C:\TEST.TXT") w.Write(cb.GetUpdateCommand().CommandText) w.Close() Quellcode 7 strSQL = "SELECT Vorname, Nachname FROM tblAdressen WHERE PLZ LIKE '4%'" Dim daFilter As New OleDbDataAdapter(strSQL, cnn) Dim tblLokaleAdressen As New DataTable daFilter.Fill(tblLokaleAdressen) For Each row In tblLokaleAdressen.Rows Console.WriteLine(row.Item("Vorname").ToString + " " + _ row.Item("Nachname").ToString) Next tblLokaleAdressen = Nothing daFilter.Dispose() Quellcode 8 computer.haufe.de Access, SQL & .NET PREVIEW 9 Know-how Einführung in ADO.NET strSQL = "SELECT Vorname, Nachname FROM tblAdressen WHERE PLZ = @PLZ" Dim daParamFilter As New OleDbDataAdapter(strSQL, cnn) daParamFilter.SelectCommand.Parameters.Add("@PLZ", OleDbType.VarChar, 50).Value = _ "79102" Dim tblParamAdressen As New DataTable daParamFilter.Fill(tblParamAdressen) For Each row In tblParamAdressen.Rows Console.WriteLine(row.Item("Vorname").ToString + " " + _ row.Item("Nachname").ToString) Next tblParamAdressen = Nothing daParamFilter.Dispose() Quellcode 9 Dim RowsSelected() As DataRow RowsSelected = tblAdressen.Select("PLZ = '79102'") Dim i As Integer For i = 0 To RowsSelected.Length - 1 Console.WriteLine(RowsSelected(i).Item("Vorname").ToString + " " _ + RowsSelected(i).Item("Nachname").ToString) Next Quellcode 10 Statements oder vielen Parametern helfen Ihnen benannte Parameter, Programmierfehler zu vermeiden. niert ein neues DataSet und füllt es mit der Unternehmens- und der Adressentabelle (s. Quellcode 11). Wenn Sie die Daten nicht direkt bei der Abfrage selektieren können, benutzen Sie am besten die Select-Methode des DataTable-Objekts. Im Beispiel fungiert die Unternehmenstabelle als Mastertabelle. Die Adressentabelle enthält das Feld UnternehmenID, mit dem eine Adresse optional einem Masterdatensatz in der Unternehmenstabelle zugeordnet werden kann. Die Methode selektiert die DataRow-Objekte aus einem DataTable-Objekt, die dem angegebenen Filterkriterium entsprechen. Als Ergebnis erhalten Sie ein Array von DataRow-Objekten mit den gefundenen Zeilen (s. Quellcode 10). 4.4 Das DataSet-Objekt Mit dem DataSet-Objekt können Sie mehrere Datentabellen gleichzeitig im Speicher halten. Dies hat den Vorteil, dass Sie mehrere relational verknüpfte Tabellen in einem einzigen Objekt verwalten können. Das folgende Beispiel defi- 10 Access, SQL & .NET PREVIEW Eine solche Relation können Sie dem DataSet mit folgenden Anweisungen hinzufügen (s. Quellcode 12). Wenn die Relation einmal definiert ist, können Sie nach Bedarf in den Zeilen der Master- und der Detailtabelle blättern. Besonders interessant ist dabei die Möglichkeit, zu einem Datensatz der Mastertabelle eine Liste der Detaildatensätze abzufragen. Die GetChildRows-Methode füllt hierzu ein Array mit den Row-Objekten der computer.haufe.de Know-how Einführung in ADO.NET Child-Tabelle. Das folgende Beispiel durchläuft alle Datensätze der Unternehmenstabelle und zeigt die jeweils zugeordneten Datensätze der Adressentabelle an (s. Quellcode 13). 5 Zusammenfassung und Ausblick Der obige Beitrag beschreibt die wichtigsten Objekte für den Zugriff auf MDBDatenbankdateien mit Microsoft .NET. Darüber hinaus können Sie mit ADO.NET auch auf andere Datenquellen wie Textdateien, XML-Dateien, SQL Server-Datenbanken und Oracle-Datenbank zugreifen. Mit ODBC erschließen Sie sich zudem ein nahezu unbegrenztes Potenzial an Datenformaten. Die Daten aller Formate lassen sich in DataTable- und DataSet-Objekte laden und dort gemeinsam verarbeiten. Mit diesen Objekten erhalten Sie deshalb einen relativ hohen Grad der Abstraktion. Aufgrund der verbindungslosen Speicherung der Daten sind die Objekte sowohl für Windows- als auch für WebAnwendungen geeignet. Dim ds As New DataSet strSQL = "SELECT * FROM tblUnternehmen" Dim daParent As New OleDbDataAdapter(strSQL, cnnString) daParent.Fill(ds, "tblUnternehmen") strSQL = "SELECT * FROM tblAdressen" Dim daChild As New OleDbDataAdapter(strSQL, cnnString) daChild.Fill(ds, "tblAdressen") Quellcode 11 Dim colParent, colChild As DataColumn colParent = ds.Tables("tblUnternehmen").Columns("UnternehmenID") colChild = ds.Tables("tblAdressen").Columns("UnternehmenID") Dim relUnternehmenAdressen As New DataRelation("relUnternehmenAdressen", colParent, _ colChild) ds.Relations.Add(relUnternehmenAdressen) Quellcode 12 ' Master- und Childatensätze anzeigen Dim ChildRows() As DataRow Dim ParentRow As DataRow Dim i As Integer For Each ParentRow In ds.Tables("tblUnternehmen").Rows Console.WriteLine("**** " + ParentRow.Item("Unternehmen").ToString _ + "**** ") ChildRows = ParentRow.GetChildRows(relUnternehmenAdressen) For i = 0 To ChildRows.Length - 1 Console.WriteLine(ChildRows(i).Item("Vorname").ToString + " " + _ ChildRows(i).Item("Nachname").ToString) Next Next Quellcode 13 computer.haufe.de Access, SQL & .NET PREVIEW 11