26.7 Objekte vom Typ DataView
Wenn Sie die Select-Methode der DataTable benutzen, sollten Sie sich über zwei Nachteile im Klaren sein:
- Sie arbeitet nicht effizient mit den Daten.
- Der Rückgabewert ist immer ein DataRow-Array, das von Windows-Forms und Webformularen nicht unterstützt wird.
Diese Nachteile haben DataView-Objekte nicht. Sie repräsentieren eine einfache Möglichkeit, verschiedene Sichten auf einen Datenbestand anzubieten – ähnlich den Views einer Datenbank. Ausgangsbasis für eine DataView ist jedoch kein SQL, sondern eine DataTable. So könnte man zum Beispiel eine DataTable mit den Bestellungen eines Kunden füllen und eine DataView erzeugen, die nur die Bestellungen anzeigt, die noch offen sind. Eine weitere DataView könnte gleichzeitig alle Bestellungen darstellen, die schon abgeschlossen sind.
Der wesentliche Vorteil dieser Methode ist, dass im Gegensatz zur Select-Methode mehrere Sichten gleichzeitig angezeigt werden können, ohne eine Kopie der Daten zu erstellen. Außerdem werden DataView-Objekte automatisch aktualisiert, sobald sich die Daten in der DataTable ändern. Zudem bietet eine DataView eine bessere Unterstützung für das Filtern von Daten als das DataTable-Objekt.
Ein DataView-Objekt verwaltet keine eigene Kopie der Daten, sondern referenziert die Tabellendaten. Bitte beachten Sie, dass ein DataView-Objekt nur mit einer Tabelle verbunden ist: Daten aus verschiedenen Tabellen lassen sich also nicht kombinieren.
26.7.1 Initialisierung
Die Klasse DataView definiert drei Konstruktoren. Wenn Sie den parameterlosen Konstruktor benutzen, müssen Sie in einer weiteren Anweisung das DataView-Objekt mit einer DataTable verknüpfen. Dazu dient die Eigenschaft Table:
Dim dv As DataView = New DataView() dv.Table = ds.Tables(0)
Der einfach parametrisierte Konstruktor nimmt die Referenz auf die DataTable entgegen:
Dim dv As DataView = New DataView(ds.Tables(0))
Der dritte Konstruktor erinnert an die Select-Methode der Klasse DataTable. Im ersten Parameter erwartet er die Referenz auf die DataTable, im zweiten wird ein Filterkriterium angegeben, im dritten das Sortierkriterium und schließlich im vierten ein Wert vom Typ DataRowViewState.
Dim dv As DataView = New DataView(tbl, "", "", DataViewRowState.Unchanged)
Der letzte Konstruktor weist den Eigenschaften
- Table
- RowFilter
- Sort
- RowStateFilter
der DataView die gewünschten Werte zu.
26.7.2 Zugriff auf die Datenzeilen
Während Sie über die Eigenschaft Rows einer DataTable an die Auflistung aller Datenzeilen einer DataTable gelangen, verhält sich eine DataView selbst wie eine Collection. Sie können sie daher in einer For Each-Schleife durchlaufen. Die zurückgelieferte Datenzeile ist vom Typ DataRowView.
Die DataRowView werten Sie aus, indem Sie dem Indexer den Bezeichner der Spalte oder dessen Index übergeben:
Dim dv As DataView = New DataView(ds.Tables("Artikel")) For Each rowView As DataRowView in dv Console.WriteLine(rowView("ProductName")) Next
Als Auflistung verfügt eine DataView über die Eigenschaft Count, die die Anzahl der DataRowView-Objekte zurückliefert (praktisch für For-Schleifen).
26.7.3 Spalten durchsuchen
Die Find-Methode einer DataView dient dazu, eine ganz bestimmte Datenzeile zu suchen. Dazu wird der Sort-Eigenschaft zuvor ein einzelner Spaltenbezeichner zugewiesen, optional gefolgt von ASC (aufsteigend) oder DESC (absteigend). Der Find-Methode wird dann der Wert übergeben, nach dem in der unter Sort angegebenen Spalte gesucht wird.
Die Find-Methode gibt den Index der gefundenen Datenzeile in der DataView zurück oder -1, wenn keine passende Datenzeile gefunden wurde:
Dim dv As DataView = New DataView(ds.Tables(0))
dv.Sort = "ProductName"
Dim index As Integer = dv.Find("Chai")
If index <> –1 Then
Console.WriteLine("Artikel: {0}", dv(index)("UnitPrice"))
Else
Console.WriteLine("Keine Datenzeile gefunden.")
End If
26.7.4 Mehrdeutige Suchergebnisse
Die Find-Methode einer DataRowCollection und die Find-Methode einer DataView ähneln sich, denn beide liefern nur eine Datenzeile zurück: Die Find-Methode der DataRowCollection tut das, weil der zu suchende Primärschlüssel prinzipbedingt eindeutig ist, und die Find-Methode der DataView tut das, weil sie per Definition nur einen Integer-Wert liefert.
Wenn Sie zum Beispiel eine Sicht auf die Tabelle der Lieferanten erstellen und der Sort-Eigenschaft eine Stadt übergeben, könnte es sein, dass mehrere Lieferanten in der angegebenen Stadt sesshaft sind. In diesem Fall ist die Find-Methode ungeeignet. Eine DataView stellt für solche Fälle die Methode FindRows bereit, die ein DataRowView-Array liefert:
Dim dv As DataView = New DataView(ds.Tables(0))
dv.Sort = "CategoryID"
Dim rowArr() As DataRowView = dv.FindRows(1)
For Each row As DataRowView in rowArr
Console.WriteLine("Artikel: {0}", row("ProductName"))
Next
Das Codefragment druckt die Artikel der Tabelle Products mit der Kategorie-Nummer 1.
26.7.5 Datenfilter
Die Eigenschaft RowFilter spezifiziert, analog zur Select-Methode der DataTable, einen Filterausdruck zur Selektion von Datenzeilen in der Sicht. Das ist fast identisch zu einer WHERE-Klausel in einer SQL-Abfrage, es fehlt nur das WHERE selbst.
Dim dv As DataView = New DataView(ds.Tables(0))
dv.RowFilter = "ProductName LIKE 'C*'"
For Each rowView As DataRowView in dv
Console.WriteLine(rowView("ProductName"))
Next
26.7.6 Statusfilter
Die Eigenschaft RowStateFilter akzeptiert Werte der Enumeration DataViewRowState (siehe Tabelle 26.8). Während Select in DataTable für ModifiedCurrent und ModifiedOriginal die gleiche Ausgabe erzeugt, greift DataView auf die aktuellen bzw. die ursprünglichen Werte zu.
Dim dv As DataView = New DataView(ds.Tables(0))
dv.RowStateFilter = DataViewRowState.Added | DataViewRowState.Deleted
For Each rowView As DataRowView in dv
Console.WriteLine(rowView("ProductName"))
Next
26.7.7 Änderungen
Eine DataView ist nicht statisch. Sie können zusätzliche DataRowView-Objekte hinzufügen, eine DataRowView löschen oder deren Inhalt ändern.
Um eine DataRowView hinzuzufügen, verwenden Sie die Methode AddNew in DataView. Sie gibt ein neues DataRowView-Objekt zurück, dessen Spalten mit Daten gefüllt werden. Zum Schluss muss auf der DataRowView die Methode EndEdit aufgerufen werden.
Die Änderung ähnelt der einer DataRow. Mit BeginEdit wird die Änderung eingeleitet und mit EndEdit abgeschlossen. Ein Abbruch erfolgt mit CancelEdit, während Delete die Zeile löscht. Alles sind Methoden des DataRowView-Objekts.
Das folgende Beispielprogramm zeigt Ihnen alle zuvor beschriebenen Änderungsmöglichkeiten. Ausgegeben werden am Ende des Programms nur die geänderten DataRowViews. Dazu wird der Eigenschaft RowStateFilter eine passende Kombination aus den erforderlichen DataRowViewState-Konstanten übergeben:
'...\ADO\DataSet\Select.vb |
Option Strict On Imports System.Data.Common, System.Data.SqlClient Namespace ADO Module Sichten Sub Test() Dim conn As DbConnection = New SqlConnection() conn.ConnectionString = "Data Source=(local);" & _ "Initial Catalog=Northwind;Integrated Security=sspi" Dim cmd As DbCommand = New SqlCommand() cmd.CommandText = "SELECT ProductName, UnitPrice FROM Products" cmd.Connection = conn Dim ds As New DataSet() Dim da As DbDataAdapter = New SqlDataAdapter() da.SelectCommand = cmd da.Fill(ds) ' DataView erzeugen Dim dv As DataView = New DataView(ds.Tables(0)) ' DataRowView hinzufügen Dim newRow As DataRowView = dv.AddNew() newRow("ProductName") = "Schokolade" newRow("UnitPrice") = 15.99 newRow.EndEdit() ' DataRowView ändern dv(0).BeginEdit() dv(0)("ProductName") = "Eisbein" dv(0).EndEdit() ' DataRowView löschen dv(1).Delete() ' Ausgabe der DataView dv.RowStateFilter = DataViewRowState.Added Or _ DataViewRowState.Deleted Or DataViewRowState.ModifiedOriginal For Each rowView As DataRowView In dv Console.WriteLine(rowView("ProductName")) Next Console.ReadLine() End Sub End Module End Namespace
26.7.8 DataView in DataTable umwandeln
Ihnen liegt eine DataView vor, und Sie möchten diese nun als DataTable speichern? Kein Problem, denn mit der Methode ToTable werden alle Datenzeilen in eine DataTable kopiert.
Da ToTable überladen ist, haben Sie mehrere Alternativen, diesen Vorgang zu steuern. So können Sie den Namen der DataTable schon beim Methodenaufruf festlegen und die Spalten festlegen. die der DataTable übergeben werden sollen. In einem weiteren Parameter spezifizieren Sie, ob die resultierende DataTable nur eindeutige Zeilen enthält, basierend auf den angegebenen DataColumns.
Ein Beispiel mit ToTable schließt dieses Kapitel ab. Zuerst werden die Spalten ProductName, UnitPrice und UnitsInStock der Tabelle Products in eine DataTable geladen. Eine DataView beschränkt die Sicht auf einen Teilbereich dieser DataTable und enthält nur die Datenzeilen der Artikel, die mit dem Buchstaben »C« beginnen und deren Einzelpreis kleiner 30 ist. Mit
Dim tbl As DataTable = dv.ToTable( _
"C_Products", False, New String() {"UnitPrice", "ProductName" })
wird die DataView danach in eine DataTable namens C_Products geschrieben. Die neue DataTable enthält nur die Spalten UnitPrice und ProductName. Der boolesche Parameter legt fest, ob alle Zeilen eindeutig sind. Er ist hier auf False festgelegt, sodass auch zwei inhaltsgleiche Zeilen in der resultierenden DataTable erscheinen dürfen.
'...\ADO\DataSet\ToTable |
Option Strict On
Imports System.Data.Common, System.Data.SqlClient
Namespace ADO
Module ToTable
Sub Test()
Dim conn As DbConnection = New SqlConnection()
conn.ConnectionString = "Data Source=(local);" & _
"Initial Catalog=Northwind;Integrated Security=sspi"
Dim cmd As DbCommand = New SqlCommand()
cmd.CommandText = _
"SELECT ProductName, UnitPrice, UnitsInStock FROM Products"
cmd.Connection = conn
Dim ds As New DataSet()
Dim da As DbDataAdapter = New SqlDataAdapter()
da.SelectCommand = cmd
da.Fill(ds)
' DataView erzeugen
Dim dv As DataView = New DataView(ds.Tables(0))
dv.RowFilter = "ProductName LIKE 'C*' AND UnitPrice < 30"
' Umwandlung
Dim tbl As DataTable = dv.ToTable( _
"C_Products", False, New String() {"ProductName", "UnitPrice"})
For Each row As DataRow In tbl.Rows
Console.WriteLine("{0,-30}{1}", row(0), row(1))
Next
Console.ReadLine()
End Sub
End Module
End Namespace
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.