3 Daten mit ADO.NET anzeigen Dieses Kapitel enthält folgende Abschnitte: 왘 Daten mit dem Objekt DataReader laden 왘 Ergebnisse vom SQL Server mit dem Objekt DataTable laden 왘 Datensätze mit dem Objekt DataTable suchen 왘 Datensätze mit dem Objekt DataView filtern und sortieren Die ActiveX-Datenobjekte (ADO) wurde vor einigen Jahren als Lösung für den Zugriff auf Daten eingeführt, die in verschiedener Form vorliegen können – also nicht nur im lokalen Netzwerk (LAN), sondern auch im Internet. ADO war eine neue Generation des Datenzugriffs, der die Remote-Datenobjekte (RDO) und Data Acess Objects (DAO) ersetzte, ursprünglich entwickelt für die Datenbank-Engine JET. JET war eigentlich für Microsoft Access entwickelt worden und wurde später auch für kleinere und mittlere Datenbanken und ein- oder zweischichtige Datenbanklösungen verwendet. Dann kam ADO.NET. Unterschiede zwischen ADO und ADO.NET ADO und ADO.NET unterscheiden sich in mancher Hinsicht: 왘 ADO arbeitet mit verbundenen Daten: das heißt, beim Zugriff auf Daten für eine Anzeige oder Aktualisierung der Daten in Echtzeit mit einer Verbindung, die zu jeder Zeit bestehen muss. Beim Programmieren spezieller Routinen müssen die Daten in temporäre Tabellen eingelesen werden. 왘 ADO.NET arbeitet mit Daten, die nicht verbunden sind. Beim Datenzugriff erstellt ADO.NET mit Hilfe von XML eine Kopie der Daten. ADO.NET hält die Verbindung nur so lange offen, bis die Daten herunter geladen oder erforderliche Aktualisierungen ausgeführt sind. Dies macht ADO.NET besonders effizient für Web-Anwendungen. .NetSolutions 113 Daten mit ADO.NET anzeigen 왘 ADO besitzt ein Hauptobjekt, das für die Referenzierung auf Daten benutzt wird: das Objekt Recordset. Dieses Objekt bieten im Grunde nur eine einzelne Tabellenansicht der Daten, auch wenn mehrere Tabellen zu einer neuen Sammlung von Datensätzen verknüpft werden können. Mit ADO.NET können Sie auf mehrere Objekte zurückgreifen, die den Datenzugriff auf verschiedene Weise ausführen. Das Objekt DataSet ermöglicht es, das relationale Modell einer Datenbank zu speichern. Damit lassen sich Kundendaten und Bestellungen in jeder zugehörigen Tabelle einzeln einlesen und aktualisieren. 왘 Mit ADO lassen sich nur clientseitige Cursor erstellen, während in ADO.NET zwischen client- oder serverseitigem Cursor gewählt werden kann. In ADO.NET behandeln Klassen die Arbeit der Cursor. Dadurch kann der Entwickler entscheiden, was besser ist. Bei der Entwicklung von Internet-Anwendungen ist dies ein entscheidender Faktor für die Anwendungseffizienz. 왘 Während ADO zwar erlaubt, mit Datensätzen im XML-Format zu arbeiten, ist dies in ADO.NET zum Standard geworden. Daten werden primär mit XML bearbeitet. Dies ist sehr komfortabel, wenn Sie mit anderen Anwendungen arbeiten und bei der Arbeit mit Firewalls sehr hilfreich, da die Daten als HTML und XML weitergereicht werden. Objekte in ADO.NET Wie bereits erwähnt, ist das Hauptobjekt von ADO.NET das Objekt DataSet. In Abbildung 3.1 ist das Objekt DataSet mit seinen Eigenschaften, Methoden und zusätzlichen Objekten dargestellt. Werfen Sie einen Blick auf Tabelle 3.1 um eine kurze Beschreibung zu jenen Objekt zu lesen, die Sie in diesem How-To verwenden werden. Tabelle 3.1: ADO.NET-Objekte für die Bearbeitung von Daten Objekt Beschreibung DataSet Dieses Objekt wird zusammen mit anderen Datensteuerelementen verwendet und speichert die Ergebnisse, die von Befehlen und Datenadaptern geliefert werden. Anders als das Objekt Recordset von ADO und DAO liefert DataSet eine hierarchisch gegliederte Übersicht über die Daten. Mit den Eigenschaften und Auflistungen des Objekts DataSet erhalten Sie allgemeine Beziehungen, individuelle Tabellen, Zeilen und Spalten. DataTable Eines der Objekte von DataSet: Das Objekt DataTable ermöglicht die Bearbeitung der Datenwerte in einer einzelnen Tabelle. DataTable ist dem Objekt Recordset aus ADO ähnlich. 114 Objekte in ADO.NET Tabelle 3.1: ADO.NET-Objekte für die Bearbeitung von Daten (Forts.) Objekt Beschreibung DataView Mit diesem Objekt lassen sich Daten filtern und sortieren, wobei die Daten in den verschiedensten Ansichten dargestellt werden können. Jede Datentabelle hat eine Standardansicht, die den Ausgangspunkt bildet, sich aber ändern und auch in einer veränderten Ansicht speichern lässt. DataRow Dieses Objekt ermöglicht die Bearbeitung der Zeilen in einer Datentabelle. Es dient als eine Art Zwischenspeicher für die Daten, die sich durch Hinzufügen, Löschen und Ändern der Datensätze bearbeiten lassen. DataColumn Dieses Objekt liefert Informationen auf der Spaltenebene. Sie können Schemainformationen und Informationen zu den Daten abrufen, die dieses Objekt verwenden. Angenommen, Sie möchten ein Listenfeld mit Feldnamen erstellen, so können Sie die DataColumn-Auflistung durchlaufen und alle Feldnamen von dort laden. PrimaryKey Dieses Objekt dient dazu, einen Primärschlüssel für die Datentabelle anzugeben. Auf diese Weise lässt sich der Methode Find einer Datentabelle übermitteln, welche Spalte zu verwenden ist. DataSet DataRelationCollection ExtendedProperties DataTableCollection DataTable DataRowCollection DataView DataRow ChildRelations ParentRelations Constraints DataColumnCollection ExtendedProperties PrimaryKey DataColumn ExtendedProperties Bild 3.1: ADO.NET hat mehr Objekte als ADO. .NetSolutions 115 Daten mit ADO.NET anzeigen .Net enthält ebenfalls Klassen, Datenprovider genannt, die mit ADO.NET-Objekten für den Datenzugriff zusammenarbeiten. Einige dieser Objekte sind in Abbildung 3.2 zu sehen. Hinweis Ihre Visual-Studio-.NET-Anwendung besteht aus einer oder mehreren Assemblies. Jede Assembly enthält einen oder mehrere Namespaces. Die Namespaces wiederum bestehen aus einer oder mehreren Klassen (Objekten). Der Namespace für Ihre OleDb-Objekte ist System.Data.OleDb. Sie finden diese Objekte mit Hilfe des Objektbrowsers. In Tabelle 3.2 finden Sie eine kurze Beschreibung der Objekte, die Sie in diesem How-To verwenden werden. Namespace für OleDb-Provider System Namespace für SqlClient-Provider System Data Data OleDb SqlClient OleDbCommand SqlCommand OleDbConnection SqlDbConnection OleDbDataAdapter SqlDbDataAdapter OleDbDataReader SqlDbDataReader OleDbParameter SqlDbparameter Bild 3.2: Verwenden Sie entweder OleDb-Klassen oder für eine bessere Performance SQLClient-Klassen. Tabelle 3.2: NET-Datenproviderklassen für die Bearbeitung von Daten Objekt Beschreibung Command Ähnlich dem ADO-Objekt Command ermöglicht dieses Objekt die Ausführung gespeicherter Prozeduren im Code. Anders als mit der ADO-Version können Sie hiermit jedoch mit der Methode ExecuteReader das Objekt DataReader erstellen. 116 Objekte in ADO.NET Tabelle 3.2: NET-Datenproviderklassen für die Bearbeitung von Daten (Forts.) Objekt Beschreibung Connection Dieses Objekt öffnet eine Verbindung zum Server und zu der Datenbank, mit der Sie arbeiten möchten. Anders als beim ADO-Objekt Connection hängt die Art der geöffneten Verbindung von dem Objekt ab, mit dem Sie arbeiten, z.B. DataReader oder DataSet. DataAdapter Als wirkliches Arbeitstier ermöglicht das Objekt DataAdapter das Erstellen von SQL-Anweisungen und das Ausfüllen von Datasets mit Daten. Es erstellt auch andere notwendige Aktionsabfragen wie die ADO.NET-Befehlsobjekte Insert, Update und Delete. DataReader Dieses Objekt erstellt einen schreibgeschützten nur vorwärts gerichteten Datenstrom, der es ermöglicht, Steuerelemente wie Listenfelder und ComboBoxes schnell zu füllen. Parameter Mit diesem Objekt können Sie einen Parameter (oder mehrere) angeben, die von DataAdapter-Objekten verwendet werden können. Tipp In Kapitel 1, »Entwicklung von Windows Forms mit gebundenen Steuerele- menten«, wurde erwähnt, dass sich die OleDb-Datensteuerelemente für verschiedene Server eigenen, während die SQLClient-Steuerelemente streng für SQL Server vorbehalten sind. Dasselbe gilt auch für diese Objekte. Wenn Sie wissen, dass Sie nur mit einem SQL Server arbeiten, erhalten Sie mit den SQLClient-Objekten eine bessere Performance, da eine Ebene herausgenommen ist. In den folgenden How-Tos werden Sie alle Elemente kennen lernen, die in den beiden vorherigen Tabellen aufgelistet wurden. Tipp Wenn Sie bei ADO bleiben müssen oder einfach nur starrköpfig sind, fin- den Sie in Anhang A, »Desktop-Entwicklung mit ADO«, weitere Informationen hierzu. Obwohl ADO.NET manchmal einen etwas höheren Arbeitsaufwand erfordert, um bestimmte Aufgaben auszuführen, die sich auch mit ADO ausführen ließen, ist die damit verbundene Leistungsstärke und Flexibilität diesen Anstieg der Lernkurve wert. Hinweis Dieses Kapitel wurde zwar mit Windows Forms geschrieben, doch die Mehrzahl der Objekte lässt sich auch mit Web Forms durch Verwendung von ADO.NET mit ASP.NET benutzen. Dies werden Sie in Kapitel 5, »Mit Daten in Web Forms arbeiten«, sehen. Sie werden verschiedene Methoden kennen lernen, mit denen sich dasselbe Ziel erreichen lässt. Wann und wie Sie diese Methoden einsetzen, hängt vom jeweiligen Szenario ab. .NetSolutions 117 Daten mit ADO.NET anzeigen CD Alle Beispiele aus diesem Kapitel finden Sie in der Lösung VB.Net – Chapter 3 auf der beiliegenden CD-ROM. 3.1 Daten mit dem Objekt DataReader laden In Kapitel 1 haben Sie erfahren, wie sich datengebundene OleDb-Steuerelemente auf Formularen verwenden lassen. Manche Programmierer ziehen es vor, ungebundene Steuerelemente zu benutzen, um dieselben Aufgaben auszuführen. Das Objekt DataReader bietet die Möglichkeit, eine Liste von Elementen auf effektivere Weise in ein Listenfeld einzufügen, weil es sich um ein Objekt handelt, das schreibgeschützt ist und nur in eine Richtung liefert. In diesem How-To wird beschrieben, wie ein begrenztes ListBox-Steuerelement mit dem Objekt DataReader erstellt wird. Sie möchten eine begrenzte Liste von Kunden erstellen. Es sollten keine gebundenen Steuerelemente verwendet werden, weil Sie ein cooler VB-Entwickler sind und wissen möchten, wie es besser geht. Sie haben gehört, dass es eine schnelle Möglichkeit dafür mit dem Objekt DataReader gibt. Wie lassen sich Daten mit dem Objekt DataReader einlesen, um diese Aufgabe auszuführen? Technik Für dieses How-To verwenden Sie das ListBox-Steuerelement und laden mit Hilfe des Objekts DataReader Elemente in das Listenfeld. Um das Objekt DataReader zu erhalten, werfen Sie einen Blick auf das Objekt Command. Das Objekt Command funktioniert in .NET ähnlich wie das ADO-Command. Das heißt, Sie weisen den Namen der gespeicherten Prozedur oder die SQL-Anweisung sowie die verwendete Verbindung der Eigenschaft CommandText auf dieselbe Weise zu. Ein Unterschied besteht darin, dass Sie die Methode Open des Objekts Command und dann die Methode ExecuteReader benutzen werden, um das Objekt DataReader zu erstellen. Dann werden Sie die Methode Read des Objekt DataReader dazu verwenden, zwei Aufgaben auszuführen. Erstens: Bei der Verwendung in einer Schleife wird auf datareader.Read() getestet, um zu prüfen, ob die Schleife beendet werden soll und ob die Zeilen durchsucht werden sollen, die das Objekt DataReader liefert. Zweitens: Nachdem DataReader gefüllt ist und die Zeilen durchlaufen wurden, werden die Daten in das ListBox-Steuerelement eingelesen. Sie verwenden die Methoden Clear und Add, wie auch in VB 6 üblich. Zusätzlich arbeiten Sie mit den Methoden BeginEdit und EndEdit, die das Laden des ListBox-Steuerelements beschleunigen, wenn eine große Datenmenge geladen werden soll. 118 Daten mit dem Objekt DataReader laden Um dieses Beispiel in der Entwurfsansicht zu zeigen, öffnen Sie das Formular frmHowTo3_1.vb in der Lösung zu Chapter 3. Übung Öffnen Sie die Lösung VB.NET – Chapter 3. Im Hauptformular klicken Sie auf die Schaltfläche mit der Beschriftung HOW-TO 3.1. Wenn das Formular geladen ist, klicken Sie auf die Befehlsschaltfläche Load List. Sie sehen, wie sich die Liste darunter mit allen Firmennamen füllt, die mit dem Buchstaben A beginnen. Sie werden ein Formular erstellen, das dem in Kapitel 1 erstellten Formular ähnlich ist. Doch anstatt gebundene Steuerelemente zu verwenden, werden Sie Code mit ADO.NET benutzen, um das ListBox-Steuerelement zu füllen. 1. Erstellen Sie ein Windows Form. Fügen Sie darauf die Steuerelemente Label, TextBox, ListBox und BUTTON ein und setzen Sie dafür die in Tabelle 3.3 aufgelisteten Eigenschaften. Tabelle 3.3: Eigenschaftseinstellungen für die Steuerelemente Label, TextBox, ListBox und Button Objekt Eigenschaft Einstellung Label NAME Label1 TEXT Customer NAME txtCustLimit TEXT A ListBox NAME lstCustomers Button NAME btnLoadList TEXT Load List TextBox Beachten Sie, dass für das ListBox-Steuerelement keine DataBindings-Eigenschaften definiert wurden. Abbildung 3.3 zeigt, wie das Formular aussehen sollte. 2. Ehe Sie Code erstellen, der dem Click-Ereignis des Buttons btnLoadList hinzugefügt wird, müssen Sie eine Supportroutine erfinden, um den Verbindungsstring zu erstellen. Diese Funktion namens BuildCnStr ist in Listing 3.1 zu finden. Diese Funktion nimmt einen Server- und Datenbanknamen auf, die an sie weitergereicht wurde, und erstellt einen Verbindungsstring. .NetSolutions 119 Daten mit ADO.NET anzeigen Bild 3.3: Ordnen Sie die Steuerelemente auf dem neuen Formular so an wie hier abgebildet. Listing 3.1: modGeneralRoutines.vb – Verbindungsstring erstellen Function BuildCnnStr(ByVal strServer As String, _ ByVal strDatabase As String) As String Dim strTemp As String strTemp = "Provider=SQLOleDB; Data Source=" & strServer & ";" strTemp &= "Initial Catalog=" & strDatabase & ";" strTemp &= "Integrated Security=SSPI" Return strTemp End Function Obwohl Sie auch eine Routine erstellen könnten, die das Objekt Connection zurückgibt, ist es die flexiblere Variante, einen String zu verwenden. Im nächsten Schritt werden Sie erfahren, wie BuildCnnStrg aufgerufen wird. 3. Fügen Sie dem Click-Ereignis des Buttons btnLoadList den folgenden Code aus Listing 3.2 hinzu. In dieser Routine wird ein SQL-String erzeugt und im String strSQL gespeichert. In die Eigenschaft TEXT des Steuerelements TextBox wird ein 120 Daten mit dem Objekt DataReader laden Literal einfügt. Dann wird mit einem Try-Catch-End-Try-Block eine neue Instanz des OleDbCommand-Objekts namens ocmdCust erstellt. Die Routine folgt dann jenen Schritten, die im Abschnitt »Technik« zu diesem How-To bereits erläutert wurden. Listing 3.2: frmHowTo3_1.vb – ListBox mit dem Objekt DataReader laden Private Sub btnLoadList_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnLoadList.Click Dim ocmdCust As OleDb.OleDbCommand Dim odrCust As OleDb.OleDbDataReader Dim strSQL As String '—Erstellt den SQL-String strSQL = "Select CompanyName From Customers Where CustomerID Like '" & Me.txtCustLimit.Text & "%’" '—Fängt die Ausnahme auf Try '—Erstellt eine Instanz von command ocmdCust = New OleDb.OleDbCommand() With ocmdCust '—Richtet Connection und Text für command ein .Connection = _ New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) .Connection.Open() .CommandText = strSQL '—Richtet Instanz von data reader ein odrCust = .ExecuteReader(CommandBehavior.SequentialAccess) End With '—Fügt Elemente in die ListBox ein. With lstCustomers .Items.Clear() .BeginUpdate() Do While odrCust.Read .Items.Add(odrCust.Item("CompanyName")) Loop .EndUpdate() .NetSolutions 121 Daten mit ADO.NET anzeigen End With Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try End Sub Hinweis Für VB-Entwickler ist sicher die Tatsache interessant, dass die folgenden Codezeilen ein OleDBConnection-Objekt in einer einzigen Anweisung deklarieren, initialisieren und verwenden: .Connection = _ New OleDb.OleDbConnection(BuildCnnStr("(local)", "Northwind")) Das ist neu in .NET und sehr hilfreich. Funktionsweise Wenn ein Benutzer auf die Schaltfläche BtnLoadList klickt, werden dem Objekt Command die erforderlichen Eigenschaften zugewiesen, die Verbindung wird geöffnet und die Methode ExecuteReader wird ausgeführt. Nachdem die Liste gelöscht ist, wird DataReader durchlaufen und das ListBox-Steuerelement geladen. Kommentar Die Verwendung des Objekts DataReader gehört zu den effizientesten Methoden, Daten vom Server zu holen und in Listenfelder in Anwendungen zu laden. Neben CommandBehavrior.SequentialAccess stehen auch andere Optionen zur Verfügung, die eine einfache Handhabung des Objekts DataReader ermöglichen. Erwähnenswert ist z.B. CommandBehavior.SchemaOnly, womit sich Informationen über die Spalten einholen lassen, nicht jedoch Daten. Neben der hier vorgestellten Form lässt sich das Objekt Command auch auf verschiedene andere Weisen einsetzen. Weitere Beispiele für die Verwendung des Objekts Command mit gespeicherten Prozeduren zur Ausführung von Batch-Aktionen finden Sie später in diesem Kapitel. 122 Ergebnisse vom SQL Server mit dem Objekt DataTable laden Sie haben nun erfahren, wie sich ein ListBox-Steuerelement mit einer komplett ungebundenen Technik füllen lässt. Im nächsten How-To lernen Sie, wie sich das ListBoxSteuerelement in einer halbgebundenen Form benutzen lässt, wenn nämlich die Daten zur Laufzeit gebunden werden. 3.2 Ergebnisse vom SQL Server mit dem Objekt DataTable laden Das Objekt DataReader eignet sich hervorragend für das manuelle Laden von Daten in ein ListBox-Steuerelement oder eine ComboBox, aber Sie können sich einigen Code ersparen, wenn Sie das ListBox-Steuerelement zur Laufzeit an das Objekt DataTable binden. Außerdem lässt sich damit dafür sorgen, dass Sie nicht nur den angezeigten Wert, sondern auch die Schlüsselspalte erhalten. Dieses How-To zeigt, wie ein begrenztes ListBox-Steuerelement an das Objekt DataTable gebunden wird. Das schnelle Einlesen von Informationen ist zwar wunderbar, aber Sie benötigen auch einen Rückbezug auf die Tabelle mit den Informationen und möchten dafür keine weitere Verbindung öffnen. Sie wissen, dass das Objekt DataTable diese Möglichkeit bietet. Doch wie erhalten Sie die Ergebnisse vom SQL Server mit einem DataTable-Objekt? Technik Sie werden die bereits aus How-To 3.1 bekannten Steuerelemente verwenden und ein aus Kapitel 1 bekanntes Objekt – das Objekt DataAdapter. Doch diesmal werden Sie nicht das Datensteuerelement OleDbDataAdapter benutzen, sondern stattdessen die Klasse OleDbDataAdapter aus dem Namespace System.Data.OleDb. Dabei wird eine ähnliche Technik wie beim Ausfüllen des DataSet verwendet. Sie werden den Datenadapter durch Zuweisung eines SQL-Strings und eines ConnectionObjekts instantiieren. Dann wird anstelle des Objekts DataSet das Objekt DataTable gefüllt. Da Sie nur mit den Datenwerten der Tabelle arbeiten, benötigen Sie auch nur eine Datentabelle. Auf diese Weise können Sie auf bequemere Weise nachschlagen, wie Sie im nächsten How-To erfahren werden. Im nächsten Schritt werden dem Listenfeld folgende Eigenschaften zugewiesen: 왘 DATASOURCE: Hier wird das Objekt DataTable angegeben, in diesem Fall dtCust. 왘 DISPLAYMEMBER: Hier wird die Spalte der Datentabelle angegeben, die für die Anzeige im Listenfeld verwendet werden soll. .NetSolutions 123 Daten mit ADO.NET anzeigen 왘 VALUEMEMBER: Hier wird die Spalte angegeben, deren Wert geladen werden soll, wenn ein Element im Listenfeld ausgewählt wird. Wenn Sie ein ListBox-Steuerelement mit dieser Technik programmieren, haben Sie in der Eigenschaft SelectItem Zugriff auf die Spalte ValueMember für das Listenfeld. Übung Öffnen Sie die Lösung VB.Net – Chapter 3. Im Hauptformular klicken Sie auf die Schaltfläche mit der Beschriftung HOW-TO 3.2. Wenn das Formular geladen wird, klicken Sie auf die Schaltfläche Load List. Sie sehen, wie die Liste mit Firmennamen gefüllt wird, die mit A beginnen. 1. Um Zeit zu sparen, können Sie eine Kopie des Formulars erstellen, das in How-To 3.1 erstellt wurde. 2. Ersetzen Sie das Click-Ereignis für btnLoadList mit dem in Listing 3.3 aufgeführten Code. Das war schon alles. Nachdem der erforderliche SQL-String erstellt und in strSQL gespeichert ist, wird der Datenadapter namens odaCust erstellt. Die Datentabelle dtCust wird dann mit Hilfe von odaCust gefüllt. Zuletzt werden die Eigenschaften DataSource, DisplayMember und ValueMember für das ListBox-Steuerelement lstCustomer definiert. Dies alles wird mit einem Try-Catch-End-Try-Block im Code ausgeführt. Listing 3.3: frmHowTo3_2.vb – Listenfeld mit dem Objekt DataTable laden Private Sub btnLoadList_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLoadList.Click Dim odaCust As OleDb.OleDbDataAdapter Dim dtCust As DataTable = New DataTable() Dim strSQL As String '—Erstellt den SQL-String strSQL = "Select CustomerID, CompanyName From Customers " & _ "Where CustomerID Like '" & Me.txtCustLimit.Text & "%’" '—Fängt Ausnahme Ab Try 124 Datensätze mit dem Objekt DataTable suchen '—Erstellt Instanz des Datenadapters ' und füllt Datentabelle odaCust = New OleDb.OleDbDataAdapter(strSQL, _ BuildCnnStr("(local)", "Northwind")) odaCust.Fill(dtCust) '—Bindet Daten an das Listenfeld lstCustomers.DataSource = dtCust lstCustomers.DisplayMember = "CompanyName" lstCustomers.ValueMember = "CustomerID" Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try End Sub Funktionsweise Wenn der Benutzer auf die Schaltfläche btnLoadList klickt, wird der Datenadapter namens odaCust instantiiert. Der Datenadapter wird an strSQL weitergereicht und an den Verbindungsstring, der von der Funktion BuildCnnStr erstellt wird (diese Funktion wurde im ersten How-To zu diesem Kapitel erläutert). Dann wird die Datentabelle gefüllt, und dem ListBox-Steuerelement lstCustomer werden die Eigenschaften DataSource, DisplayMember und ValueMember zugewiesen. Kommentar Mit der Verwendung des Objekts DataTable ist bereits die Bühne für das nächste How-To bereitet, in dem die Daten in das Listenfeld eingelesen werden. Zur Erinnerung: Mit dem Objekt DataTable können Sie sowohl den Datenwert anzeigen, als auch dem Datenelement auf der Spur bleiben. 3.3 Datensätze mit dem Objekt DataTable suchen Mit dem Objekt DataTable können Sie auch ein weiteres Objekt namens DataRow verwenden. Das Objekt DataRow ermöglicht es, eine bestimmte Zeile in der Datentabelle zu finden. Dies ist sinnvoll, wenn Sie Ihren Benutzern einen Suchmechanismus für .NetSolutions 125 Daten mit ADO.NET anzeigen das Formular anbieten möchten. In diesem How-To wird erläutert, wie eine bestimmte Zeile in einer Datentabelle angesteuert wird und wie sich dieselbe Datentabelle für zwei verschiedene Zwecke verwenden lässt. Nachdem das Objekt DataTable in den Arbeitsspeicher geladen ist, können Sie bestimmte Datensätze im Objekt DataTable suchen. Wie lassen sich Datensätze im Objekt DataTable finden? Technik In diesem How-To verwenden Sie anstelle des Steuerelements ListBox das Steuerelement ComboBox. Zum Laden des Steuerelements ComboBox benutzen Sie dieselbe Methode wie für ein Listenfeld. Die Vorgehensweise ändert sich erst, wenn ein Element aus der ComboBox ausgewählt wird. Sobald in der ComboBox ein Element markiert ist, wird das Ereignis SelectedIndexChanged ausgelöst. Damit erhalten Sie die Eigenschaft SelectedItem der ComboBox, die ValueMember aus der markierten Zeile enthält. Dieser Wert wird in der Methode Find des Objekts DataRow verwendet. Nachdem die Datenzeile gefunden ist, werden die zugehörigen Spalten in die Textfelder des Formulars geladen (siehe Abbildung 3.4). Bild 3.4: Diese ComboBox führt den Benutzer zu einem bestimmten Kunden. 126 Datensätze mit dem Objekt DataTable suchen Übung Öffnen Sie die Lösung VB.Net – Chapter 3. Klicken Sie im Hauptformular auf die Schaltfläche mit der Beschriftung HOW-TO 3.3. Wenn das Formular geladen wird, wählen Sie einen neuen Kunden aus dem Listenfeld aus, das sich im Steuerelement ComboBox befindet. Sie sehen, dass die Textfelder unter dem Steuerelement ComboBox jene Daten anzeigen, die zu diesem Kunden gehören. 1. Erstellen Sie ein neues Windows Form. 2. Fügen Sie, wie in Tabelle 3.4 aufgeführt, einige Label, ComboBoxes und TextBoxes in das Formular ein. Tabelle 3.4: Eigenschaftseinstellungen für die Steuerelemente Laben, TextBox und ComboBox Objekt Eigenschaft Einstellung Label NAME Label1 TEXT Customer ComboBox NAME cboCustomers Label NAME Label2 TEXT Customer ID NAME Label3 TEXT Company Name NAME Label4 TEXT Address NAME Label5 Label Label Label TEXT City TextBox NAME txtCustomerID TextBox NAME txtCompanyName TextBox NAME txtAddress TextBox NAME txtCity Sie sollten außerdem sicherstellen, dass die Eigenschaft TEXT in den TextBox-Steuerelementen leer ist. .NetSolutions 127 Daten mit ADO.NET anzeigen 3. Im Klassenmodul des Formulars fügen Sie die folgenden beiden Private-Deklarationen direkt unter jene Codezeile ein, die Vom Windows Form Designer generierter Code lautet. Private modaCust As OleDb.OleDbDataAdapter Private mdtCust As DataTable = New DataTable() Diese Codezeilen deklarieren jenen Datenadapter und jene Datentabelle, die im gesamten Formular verwendet werden. Hinweis Das vor den Namen eingefügte m weist darauf hin, dass es sich um eine Variable auf Modul- bzw. Member-Ebene handelt. Beachten Sie ferner: Obwohl diese Deklaration auf der Formular-Ebene stattfindet, bleibt die Verbindung, die für den Datenadapter verwendet wird, nicht so lange offen, wie das Formular geöffnet ist. Beim Füllen der Datentabelle ist die Verbindung geöffnet. Dann wird lokal hinter den Kulissen mit XML auf die Daten zugegriffen, und es besteht keine Serververbindung mehr. 4. Fügen Sie den Code aus Listing 3.4 in das Ereignis Load des Formulars ein. Obwohl dieser Code fast identisch ist mit dem Code zum Laden des ListBox-Steuerelements aus dem letzten How-To, definiert dieser Code modaCust mit einem SQLString und dem zu verwendenden Verbindungsstring. mdtCust wird dann mit der Methode Fill von modaCust gefüllt. Als nächstes wird das erste Element im Array DataColumn namens cd mit der Spalte CustomerID definiert und dann wird mdtCustPrimaryKey mit dem Array DataColumn definiert. Zuletzt werden die Eigenschaften DataSource, DisplayMember und ValueMember eingerichtet. Listing 3.4: frmHowTo3_3.vb – ComboBox mit dem Objekt DataTable laden Private Sub frmHowTo3_3_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim strSQL As String Dim dc(1) As DataColumn '—Fängt Ausnahme auf Try '—Erstellt Datenadapter und füllt die Datentabelel modaCust = New _ OleDb.OleDbDataAdapter("Select * From Customers", _ 128 Datensätze mit dem Objekt DataTable suchen (BuildCnnStr("(local)", "Northwind"))) modaCust.Fill(mdtCust) '—Richtet Primärschlüssel für Datentabelle ein dc(0) = mdtCust.Columns("CustomerID") mdtCust.PrimaryKey = dc '—Bindet Daten an ComboBox cboCustomers.DataSource = mdtCust cboCustomers.DisplayMember = "CompanyName" cboCustomers.ValueMember = "CustomerID" Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try End Sub Die Eigenschaft PrimaryKey, die im Code definiert wurde, wird im nächsten Schritt von der Methode Fill der Auflistung mdtCust’s Rows benötigt. 5. Dieses letzte Stück Code muss in das Ereignis SelectedIndexChanged des ComboBoxSteuerelements cboCustomers eingefügt werden. Ebenso wie im letzten Schritt, als die Datenspalte für die Eigenschaft PrimaryKey definiert wurde, wird in diesem Schritt ein Array definiert, der den Wert SelectedItem an die Methode Find weitergibt. Die Text-Eigenschaften der TextBoxes werden dann mit Hilfe der Methode ToString mit den Werten aus den zugehörigen Spalten definiert. Listing 3.5: frmHowTo3_3.vb – Datensatz in der Datentabelle suchen und den Textfeldern Werte zuweisen Private Sub cboCustomers_SelectedIndexChanged(ByVal sender As System.Object, _ ByVal e As System.EventArgs) _ Handles cboCustomers.SelectedIndexChanged Dim drCurr As DataRow Dim aFindValue(0) As Object '—Lädt das gesuchte Element und verwendet die Methode Find aFindValue(0) = cboCustomers.SelectedItem(0) drCurr = mdtCust.Rows.Find(aFindValue) '—Lädt die Felder im Formular .NetSolutions 129 Daten mit ADO.NET anzeigen txtCustomerID.Text = drCurr("CustomerID").ToString txtCompanyName.Text = drCurr("CompanyName").ToString txtAddress.Text = drCurr("Address").ToString txtCity.Text = drCurr("City").ToString End Sub Funktionsweise Wenn ein Benutzer im ComboBox-Steuerelement cboCustomer eine Auswahl trifft, sucht der Code den gewünschten Wert mit Hilfe der Methode Find in der Datentabelle mdtCust anhand der Zeilenauflistung. Die Textfelder werden dann aus der Zeile geladen, die ermittelt wurde. Kommentar Das Suchen von Datensätzen in einer Datentabelle ist mit Hilfe dieser Methoden sehr einfach. ADO.NET stellt alle notwendigen Instrumente dafür bereit – und zwar nicht nur auf einer allgemein hierarchischen Ebene, sondern bis hin zu den einzelnen Zeilen und Spalten. 3.4 Datensätze mit dem Objekt DataView filtern und sortieren Nachdem die Daten in die Datentabelle geladen sind, möchten Sie die Daten eventuell auf verschiedene Weisen filtern und in bestimmten Sortierfolgen anzeigen. Dazu können Sie das Objekt DataView verwenden. In diesem How-To wird genau erläutert und dargestellt, wie Sie das Objekt DataView zur Bearbeitung der Daten einsetzen können. Sie können die Daten zwar auch in ein DataGrid-Steuerelement einfügen und den Benutzer anhand der Spalten sortieren lassen, doch hier soll ein ComboBox-Steuerelement angezeigt werden, aus dem der Benutzer zusätzlich ein Feld aus einer Dropdown-Liste auswählen kann. Wie können Sie Datensätze mit dem Objekt DataView filtern und sortieren, um die Daten auf verschiedene Weise darzustellen? 130 Datensätze mit dem Objekt DataView filtern und sortieren Technik In diesem How-To werden viele Buttons verwendet, die Buchstaben darstellen und ein zusätzlicher Button, der alle Datensätze anzeigt. Der Datenadapter, die Datentabelle und die Datenansicht werden auf Formularebene deklariert. Eine ComboBox wird mit dem Objekt DataColumn gefüllt, indem die Namen der einzelnen Spalten aus der Datentabelle eingelesen werden. In Abbildung 3.5 sehen Sie dieses Formular in Aktion. Bild 3.5: Durch die Auswahl eines Buchstabens wird die Datenanzeige im DataGrid beschränkt. Mit den Buttons ist eine Routine verknüpft. Diese wird aufgerufen, erstellt das Objekt DataView, definiert die Eigenschaft RowFilter und weist DataView dann die Eigenschaft DataSource eines DataGrid-Steuerelements zu. Hinweis Mit lassen sich Daten anhand von Kriterien wie RowFilter CompanyName gleich »A%« filtern; es aber gibt noch eine andere Eigenschaft, mit der sich Daten auf der Basis ihres Zeilenstatus anzeigen lassen. Diese Eigenschaft heißt RowStateFilter. .NetSolutions 131 Daten mit ADO.NET anzeigen Die verfügbaren DataViewRowState-Werte für RowStateFilter sind in Tabelle 3.5 aufgeführt. Tabelle 3.5: Eigenschaftseinstellungen für die Steuerelemente Label, TextBox und ComboBox Einstellung Beschreibung Added Neue Zeilen CurrentRows Aktuelle Zeilen einschließlich unveränderter, neuer und bearbeiteter Zeilen Deleted Gelöschte Zeilen ModifiedCurrent Aktuelle Versionen, d.h. veränderte Versionen der Originaldaten (siehe ModifiedOriginal) ModifiedOriginal Die Originalversion (auch wenn Sie verändert wurde und als ModifiedCurrent verfügbar ist) None Keine OriginalRows Originalzeilen einschließlich unveränderter und gelöschter Zeilen Unchanged Unveränderte Zeile Die Eigenschaft Sort des Objekts DataView wird verwendet, wenn ein Spaltenname aus der ComboBox gewählt wird. Die aktuelle Einstellung der Eigenschaft Sort wird mit dem gewählten Spaltennamen verglichen. Entsprechen sich die Namen, wird der Ausdruck DESC an den Wert angefügt, der der Eigenschaft Sort zugewiesen ist. Übung Öffnen Sie die Lösung VB.NET How-To Chapter 3. Klicken Sie im Hauptformular auf die Schaltfläche mit der Beschriftung HOW-TO 3.4. Wenn das Formular geladen ist, klicken Sie auf einen der angezeigten Buchstaben. Im DataGrid werden die Kunden angezeigt, die mit diesem Buchstaben beginnen. Wenn Sie aus dem Dropdown-Listenfeld der ComboBox einen anderen Spaltennamen auswählen, wird das DataGrid anhand dieser Spalte sortiert. 1. Erstellen Sie ein neues Windows Form. 2. Fügen Sie das Steuerelement GroupBox und vergeben Sie als Text-Eigenschaft Click on a letter. 3. Jetzt erstellen Sie viele Buttons, die Sie innerhalb der soeben erstellten GroupBox platzieren. Die Buttons haben die in Tabelle 3.6 aufgelisteten Eigenschaften. 132 Datensätze mit dem Objekt DataView filtern und sortieren Tabelle 3.6: Eigenschaften der Buttons Objekt Eigenschaft Einstellung Button NAME btnA TEXT A NAME btnB TEXT B NAME btnC TEXT C NAME btnZ TEXT Z NAME btnAll TEXT All Button Button ... Button Button 4. Fügen Sie die Steuerelemente DataGrid, Label und ComboBox, wie in Tabelle 3.7 aufgeführt, ein. Tabelle 3.7: Eigenschaftseinstellungen für die Steuerelemente DataGrid, Label und ComboBox Objekt Eigenschaft Einstellung DataGrid NAME dgCustomers Label NAME Label1 Label TEXT Column to Sort On: ComboBox NAME cboSortColumns 5. In das Klassenmodul für das Formular fügen Sie die drei folgenden Private-Deklarationen direkt unter der Codezeile Vom Windows Form Designer generierter Code ein. Diese drei Objekte werden im gesamten Formular verwendet: Private modaCust As OleDb.OleDbDataAdapter Private mdtCust As DataTable = New DataTable() Private mdvCust As DataView = New DataView() 6. Fügen Sie den Code aus Listing 3.6 in das Load-Ereignis des Formulars ein. Dieser Code richtet zunächst den Datenadapter so ein, dass er alle Kunden in die Datentabelle mdtCust einliest. Beachten Sie, dass das DataGrid-Steuerelement an diesem Punkt noch nicht gefüllt ist. .NetSolutions 133 Daten mit ADO.NET anzeigen Die nächste Aufgabe besteht darin, cboSortColumns mit den Spaltenüberschriften zu laden, indem jede Datenspalte in mdtCust durchlaufen und dann in die ItemAuflistung in cboSortColumn eingefügt wird. Zuletzt wird die Routine SetDataViewFilter aufgerufen. Diese Routine wird in Schritt 8 erläutert. Listing 3.6: frmHowTo3_4.vb – Datentabelle für das Formular laden und Spaltennamen in ComboBox einfügen. Private Sub frmHowTo3_4_Load(ByVal sender As Object, _ ByVal e As System.EventArgs) Handles MyBase.Load Dim strSQL As String Dim dcCurr As DataColumn '—Fängt Ausnahme auf Try '—- Erstellt Datenadapter und füllt Datentabelle modaCust = New _ OleDb.OleDbDataAdapter("Select * From Customers", _ (BuildCnnStr("(local)", "Northwind"))) modaCust.Fill(mdtCust) '—Lädt Spaltennamen zur Sortierung in die ComboBox For Each dcCurr In mdtCust.Columns Me.cboSortColumns.Items.Add(dcCurr.ColumnName) Next SetDataViewFilter("B") Catch oexpData As OleDb.OleDbException MsgBox(oexpData.Message) End Try End Sub 7. Für jeden Button, der mit einem einzigen Buchstaben beschriftet ist, fügen Sie die erste in Listing 3.7 aufgeführte Subroutine in die jeweiligen Click-Ereignisse ein. Für das Steuerelement btnAll fügen Sie die zweite Subroutine in das Click-Ereignis ein. Jeder Button reicht den zugehörigen Buchstaben an die Subroutine SetDataViewFilter weiter, die im nächsten Schritt erläutert wird. Der Code für btnAll reichte einfach einen leeren String weiter. 134 Datensätze mit dem Objekt DataView filtern und sortieren Listing 3.7: frmHowTo3_4.vb – Click-Ereignisse für jeden Button Private Sub btnA_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnA.Click SetDataViewFilter("A") End Sub Private Sub btnAll_Click(ByVal sender As System.Object, _ ByVal e As System.EventArgs) Handles btnAll.Click SetDataViewFilter("") End Sub 8. Fügen Sie die Subroutine aus Listing 3.8 in das Klassenmodul des Formulars ein. Diese Routine verwendet den Buchstabenwert, der in strFilterLetter weitergegeben wurde als Parameter. Die erste Aufgabe besteht darin, die Standardansicht DefaultView des DataTable-Objekts mdtCust dem DataView-Objekt mdvCust zuzuweisen. Als nächstes wird die Eigenschaft RowFilter von mdvCust so eingerichtet, dass Sie die Spalte CompanyName mit Hilfe des Ausdrucks Like mit strFilterLetter und % (Platzhalter) vergleicht. Beachten Sie: Wenn “” an StrFilterLetter weitergereicht wird, werden alle Datensätze angezeigt. Schließlich wird mdvCust als DataSource für das DataGrid-Steuerelement dgCustomers definiert. Listing 3.8: frmHowTo3_4.vb – Eigenschaft RowFilter für das Objekt DataView setzen Sub SetDataViewFilter(ByVal strFilterLetter As String) mdvCust = mdtCust.DefaultView mdvCust.RowFilter = "CompanyName Like '" & strFilterLetter & "%’" dgCustomers.DataSource = mdvCust End Sub 9. Fügen Sie das Codefragment aus Listing 3.9 in das Ereignis SelectedIndexChanged des ComboBox-Steuerelements cboSortColumns ein. Diese Routine vergleicht die aktuelle Einstellung der Eigenschaft Sort von mdvCust mit dem aktuell in cboSortColumns ausgewählten Spaltennamen. Wenn beide identisch sind, dann wird der Spaltenname zusammen mit dem Schlüsselwort DESC (absteigende Sortierfolge) der Eigenschaft Sort zugewiesen. Sind sie nicht identisch, wird der Eigenschaft Sort nur der Spaltenname zugewiesen. Listing 3.9: frmHowTo3_4.vb – Spalte für die Sortierung angeben Private Sub cboSortColumns_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ .NetSolutions 135 Daten mit ADO.NET anzeigen Handles cboSortColumns.SelectedIndexChanged '—Prüft, ob Spalte das aktuell sortierte Feld ist. ' Wenn ja, wird die Spalte in absteigender Folge sortiert. ' Andernfalls, wird die Sortierung anhand des Spaltennamens durchgeführt. If mdvCust.Sort = Me.cboSortColumns.Text Then mdvCust.Sort = Me.cboSortColumns.Text & " DESC" Else mdvCust.Sort = Me.cboSortColumns.Text End If End Sub Funktionsweise Wenn ein Benutzer einen Buchstaben-Button anklickt, wird die betreffende Datenansicht erstellt und das DataGrid zeigt die neuen Daten an. Wenn ein Feld aus der ComboBox ausgewählt wird, wird die Eigenschaft Sort von DataView eingerichtet und das DataGrid zeigt automatisch die neue Sortierfolge an. Zusätzlich erscheint ein kleiner Pfeil in der Spaltenüberschrift. Wählt der Benutzer dieses Feld erneut aus, erfolgt eine Sortierung in absteigender Reihenfolge. Kommentar Mit dem Objekt DataView können Sie verschiedene Ansichten der Daten einrichten und diese nach Wunsch des Benutzers anzeigen. Zudem haben Sie mit DefaultViewManager Zugriff auf alle Standardansichten der Datentabelle in ihrem Dataset. Hinweis Vielleicht denken einige, eine Sortierung in einer ComboBox, wie in diesem Beispiel vorgestellt, sei überflüssig. Dieses Formular wurde aus zwei Gründen entwickelt: Erstens, um die Eigenschaft Sort des Objekts DataView zu demonstrieren. Zweitens ist es für den Benutzer angenehm. Er muss nicht durch die Spalten im DataGrid blättern, die nicht mehr am Bildschirm angezeigt werden können. Mit der ComboBox kann er auch sofort auf jene Felder zugreifen, die aktuell nicht zu sehen sind. 136