34.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 WinForms und Webformularen nicht unterstützt wird.
Diese Nachteile hat ein DataView-Objekt nicht. DataViews repräsentieren eine einfache Möglichkeit, verschiedene Sichten auf einen Datenbestand anzubieten – ähnlich den Views einer Datenbank. Ausgangsbasis für einen DataView ist jedoch kein SQL, sondern eine DataTable. So könnte man zum Beispiel eine DataTable mit den Bestellungen eines Kunden füllen und einen DataView erzeugen, die nur die Bestellungen anzeigt, die noch offen sind. Ein weiterer DataView könnte gleichzeitig alle Bestellungen darstellen, die schon abgeschlossen sind.
Im Gegensatz zur Select-Methode können mehrere Sichten gleichzeitig angezeigt werden können, ohne eine Kopie der Daten erstellen zu müssen. Außerdem werden DataView-Objekte automatisch aktualisiert, sobald sich die Daten in der DataTable ändern. Zudem bietet ein DataView eine bessere Unterstützung für das Filtern von Daten als das DataTable-Objekt.
Ein DataView-Objekt verwaltet keine eigene Kopie der Daten. Stattdessen greift ein DataView auf Daten zurück, die in einer DataTable gespeichert sind. Daten, die in zwei verschiedenen Tabellen gespeichert sind, lassen sich mit einem DataView nicht verknüpfen. Mit anderen Worten: Ein DataView kann nur auf eine DataTable zugreifen.
34.7.1 Einen »DataView« erzeugen
Die Klasse DataView definiert drei Konstruktoren. Der einfachste ist der parameterlose. Wenn Sie diesen benutzen, müssen Sie in einer weiteren Anweisung das DataView-Objekt mit einer DataTable verknüpfen. Dazu dient die Eigenschaft Table.
DataView view = new DataView();
view.Table = ds.Tables[0];
Der einfach parametrisierte Konstruktor nimmt direkt die Referenz auf die DataTable entgegen.
DataView view = 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.
DataView view = new DataView(tbl, "", "", DataViewRowState.Unchanged);
Der letztgenannte Konstruktor weist den Eigenschaften
- Table
- RowFilter
- Sort
- RowStateFilter
des DataViews sofort die entsprechenden Werte zu.
34.7.2 Auf die Datenzeilen in einem »DataView« zugreifen
Während Sie über die Eigenschaft Rows einer DataTable an die Auflistung aller Datenzeilen einer DataTable gelangen, verhält sich ein DataView selbst wie eine Collection. Sie können ihn daher in einer foreach-Schleife durchlaufen. Die zurückgelieferte Datenzeile ist vom Typ DataRowView.
Den DataRowView werten Sie aus, indem Sie dem Indexer den Bezeichner der Spalte oder dessen Index übergeben.
DataView view = new DataView(ds.Tables["Artikel"]);
foreach (DataRowView rowView in view)
Console.WriteLine(rowView["ProductName"]);
Da sich ein DataView wie eine Auflistung verhält, verwundert es nicht, dass die Eigenschaft Count die Anzahl der DataRowView-Objekte zurückliefert. Damit haben Sie die Möglichkeit, einen DataView auch in einer for-Schleife zu durchlaufen.
34.7.3 Die Eigenschaft »Sort« und die Methode »Find«
Die Find-Methode eines DataViews dient dazu, eine ganz bestimmte Datenzeile zu suchen. Allerdings ist daran eine Bedingung geknüpft: Der Sort-Methode muss zuvor ein gültiger Spaltenbezeichner übergeben werden. Sort beschreibt immer nur einen Spaltennamen, 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.
Ungewöhnlich ist der Rückgabewert der Find-Methode. Es ist ein Integer, der den Index der gefundenen Datenzeile im DataView angibt. Wird keine Datenzeile gefunden, ist der Wert –1.
DataView view = new DataView(ds.Tables[0]);
view.Sort = "ProductName";
int index = view.Find("Chai");
if (index != -1)
Console.WriteLine("Artikel: {0}", view[index]["UnitPrice"]);
else
Console.WriteLine("Keine Datenzeile gefunden.");
Listing 34.16 Suchen in einem DataView
34.7.4 Die Methode »FindRows«
Die Find-Methode einer DataRowCollection und die Find-Methode eines DataViews ähneln sich in gewisser Hinsicht, denn beide liefern nur eine Datenzeile zurück. Die Find-Methode der DataRowCollection tut dies, weil diese Find-Methode die Angabe des Primärschlüssels des zu suchenden Datensatzes erwartet, und die Find-Methode des DataViews verhält sich so, weil sie per Definition nur einen Integer-Wert liefert.
Wenn Sie aber zum Beispiel eine Sicht auf die DataTable 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 denkbar ungeeignet. Ein DataView stellt dafür die Methode FindRows bereit. Im Unterschied zu Find ist der Rückgabewert ein DataRowView-Array.
DataView view = new DataView(ds.Tables[0]);
view.Sort = "CategoryID";
DataRowView[] rowArr = view.FindRows(1);
foreach (DataRowView row in rowArr)
Console.WriteLine("Artikel: {0}", row["ProductName"]);
Listing 34.17 Mehrere Datensätze filtern
Das Codefragment beantwortet die Frage, welche Artikel der Tabelle Products der Kategorie-Nummer 1 zugeordnet werden.
34.7.5 Die Eigenschaft »RowFilter«
Die Eigenschaft RowFilter dient zum Selektieren von Datenzeilen. Sie ist vom Typ einer Zeichenfolge und unterscheidet sich nicht vom Filterausdruck der Select-Methode der DataTable. Sie geben also das Filterkriterium an, als würden Sie in einem SQL-Statement eine WHERE-Klausel definieren. Nur die Angabe von WHERE ist nicht notwendig.
DataView view = new DataView(ds.Tables[0]);
view.RowFilter = "ProductName LIKE 'C*'";
foreach (DataRowView rowView in view)
Console.WriteLine(rowView["ProductName"]);
Listing 34.18 Filterkriterium mit der Eigenschaft »RowFilter«
34.7.6 Die Eigenschaft »RowStateFilter«
Die Eigenschaft RowStateFilter akzeptiert Werte der Enumeration DataViewRowState (siehe Tabelle 34.6). Während in der Ausgabe bei einer DataTable unabhängig davon, ob bei der Filterung ModifiedCurrent und ModifiedOriginal benutzt wurden, kein Unterschied festzustellen war, werden bei einem DataView tatsächlich entweder die aktuellen oder die ursprünglichen Werte in der Ausgabe erscheinen.
DataView view = new DataView(ds.Tables[0]);
view.RowStateFilter = DataViewRowState.Added | DataViewRowState.Deleted;
foreach (DataRowView rowView in view)
Console.WriteLine(rowView["ProductName"]);
Listing 34.19 Datensätze eines bestimmten Zustands herausfiltern
34.7.7 Änderungen an einem »DataView«-Objekt
Ein DataView ist nicht statisch. Sie können zusätzliche DataRowView-Objekte hinzufügen, Sie können einen DataRowView löschen oder dessen Inhalt ändern.
Um einen DataRowView hinzuzufügen, stellt der DataView die Methode AddNew bereit. Diese gibt ein neues DataRowView-Objekt zurück, dessen Spalten mit Daten gefüllt werden können. Zum Schluss muss auf dem DataRowView die Methode EndEdit aufgerufen werden. Die Änderung ähnelt der einer DataRow. Mit BeginEdit wird die Änderung eingeleitet, und mit EndEdit wird sie abgeschlossen. Ein Abbruch kann mit CancelEdit erzwungen werden. Alles sind Methoden des DataRowView-Objekts. Um eine DataRowView zu löschen, brauchen Sie nur die Methode Delete aufzurufen.
Das folgende Beispielprogramm zeigt Ihnen alle zuvor beschriebenen Änderungsmöglichkeiten. Ausgegeben werden sollen am Ende des Programms nur die geänderten DataRowViews. Dazu wird der Eigenschaft RowStateFilter eine passende Kombination aus den erforderlichen DataRowViewState-Konstanten übergeben.
// Beispiel: ..\Kapitel 34\EditDataView
class Program {
static void Main(string[] args) {
SqlConnection con = new SqlConnection();
con.ConnectionString = "...";
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "SELECT ProductName, UnitPrice FROM Products";
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
// DataView erzeugen
DataView dv = new DataView(ds.Tables[0]);
// DataRowView hinzufügen
DataRowView newRow = 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();
dv.RowStateFilter = DataViewRowState.Added |
DataViewRowState.Deleted |
DataViewRowState.ModifiedOriginal;
// Ausgabe des DataViews
foreach (DataRowView rowView in dv)
Console.WriteLine(rowView["ProductName"]);
Console.ReadLine();
}
}
Listing 34.20 Editieren eines DataViews
34.7.8 Aus einem »DataView« eine »DataTable« erzeugen
Ihnen liegt ein DataView vor, und Sie möchten diesen nun als DataTable speichern? Kein Problem, denn mit der Methode ToTable werden alle Datenzeilen einer DataTable zugeführt, die über die Einstellung der Eigenschaft RowFilter verfügbar sind.
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 angeben, die der DataTable übergeben werden sollen. Ein weiterer Parameter gestattet es, zu spezifizieren, ob die resultierende DataTable nur eindeutige Zeilen basierend auf den angegebenen DataColumns erhält.
Ein Beispiel mit ToTable soll dieses Kapitel abschließen. Zuerst werden die Spalten ProductName, UnitPrice und UnitsInStock der Tabelle Products in eine DataTable geladen. Ein 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
DataTable tbl = dv.ToTable("C_Products", false,
new string[]{"UnitPrice", "ProductName" });
wird der DataView danach in eine DataTable geschrieben, deren Bezeichner auf C_Products festgelegt ist. Die neue DataTable enthält aber nur die Spalten UnitPrice und ProductName. Der boolesche Parameter gibt Auskunft darüber, ob alle Zeilen eindeutig sein sollen. Er ist hier auf false festgelegt, so dass durchaus auch zwei inhaltsgleiche Zeilen in der resultierenden DataTable erscheinen könnten.
// Beispiel: ..\Kapitel 34\ToTableMethod
class Program {
static void Main(string[] args){
SqlConnection con = new SqlConnection();
con.ConnectionString = "...";
SqlCommand cmd = new SqlCommand();
cmd.Connection = con;
cmd.CommandText = "SELECT ProductName, UnitPrice, UnitsInStock"’
+" FROM Products";
DataSet ds = new DataSet();
SqlDataAdapter da = new SqlDataAdapter(cmd);
da.Fill(ds);
// DataView erzeugen
DataView dv = new DataView(ds.Tables[0]);
dv.RowFilter = "ProductName LIKE 'C*' AND UnitPrice < 30";
// DataView einer DataTable übergeben
DataTable tbl = dv.ToTable("C_Products", false,
new string[] { "UnitPrice", "ProductName" });
foreach (DataRow row in tbl.Rows)
Console.WriteLine("{0,-10}{1}", row[0], row[1]);
Console.ReadLine();
}
}
Listing 34.21 Eine DataTable aus einem DataView erstellen
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.