28.3 Datenzugriff 

Nachdem wir die Form des typisierten DataSets analysiert haben, wenden wir uns nun dessen Gebrauch zu.
28.3.1 Datenzeilen ausgeben 

Das typisierte DataSet enthält die gesamte Information der ihm zu Grunde liegenden Datenbankabfrage, inklusive aller Beziehungen zwischen den Tabellen in der Abfrage. Durch die in Abschnitt 28.1.1, »Visual Studio Designer«, beschriebene Erstellung hat das typisierte DataSet also bereits alle Metainformation der Daten, ohne die Datenbank erneut abzufragen. Damit wird der Zugriff auf die Daten zum Kinderspiel:
- Erzeugen des DataSets
- Erzeugen des TableAdapters
- Abholen der Daten
- Durchlaufen der Daten
Die ersten drei Schritte sind bereits aus Abschnitt 28.2.3, »TableAdapter«, bekannt und tauchen unverändert im folgenden Codefragment auf. Der vierte Punkt ist durch den Indexer Default Property Item (Abschnitt 28.2.4, »Typisierte Tabelle«) der typisierten Tabelle besonders einfach. Dadurch können alle Zeilen der Tabelle in einer For Each-Schleife durchlaufen werden. Die Tabelle Products ist als Eigenschaft im typisierten DataSet enthalten (siehe Abschnitt 28.2.2, »Das typisierte DataSet«). Selbst der Typ der Zeile, NWDataSet.ProductsRow, ist Teil des DataSets (siehe Abschnitt 28.2.2, »Das typisierte DataSet«).
'...\ADO\DataSetTypisiert\Zeilen.vb |
Option Strict On
Imports System.Data.Common, System.Data.SqlClient
Namespace ADO
Module Zeilen
Sub Test()
Dim nw As New NWDataSet()
Dim nwa As New NWDataSetTableAdapters.ProductsTableAdapter()
nwa.Fill(nw.Products)
For Each zeile As NWDataSet.ProductsRow In nw.Products 'Indexer
Console.Write("{0} ", zeile.ProductName)
Next
Console.ReadLine()
End Sub
End Module
End Namespace
Die Ausgabe zeigt alle Produkte in der Datenbank:
...
Lager Flotemysost Mozzarella di Giovanni Röd Kaviar Longlife Tofu Rhönbräu
Klosterbier Lakkalikööri Original Frankfurter grüne Soße
28.3.2 Datenzeilen hinzufügen 

Wie in Abschnitt 28.2.4, »Typisierte Tabelle«, gezeigt wurde, hat jede Tabelle typrichtige Methoden, um neue Zeilen zu erzeugen und hinzuzufügen:
Function New<Tabelle>Row() As <Tabelle>Row |
Die hinzuzufügende Zeile hat nicht den allgemeinen Datentyp DataRow, sondern ist speziell auf die Tabelle zugeschnitten. Jede der Tabellen im typisierten DataSet stellt eine Fabrikmethode zur Erzeugung einer neuen, typrichtigen Datenzeile zur Verfügung. Jede Spalte wird über eine korrespondierende Eigenschaft gleichen Namens angesprochen (siehe Abschnitt 28.2.5, »Typisierte Zeile«). Eine Zeile darf erst hinzugefügt werden, nachdem alle Nichtschlüssel-Spalten Werte erhalten haben. Die ProductID wird vom Datenbankserver automatisch vergeben und muss daher nicht gesetzt werden. Die Fremdschlüsselspalte CategoryID darf den Wert DBNull haben, sollte aber zwecks besserer Übersichtlichkeit gesetzt werden. Abschnitt 28.3.5, »Spalten mit Null-Wert«, zeigt, wie die Null-Zuweisung erfolgen muss.
Erzeugung, Wertzuweisung und das Hinzufügen der Zeile fasst die zweite AddProductsRow-Methode zusammen. Sie ist insofern typsicherer, als dass eine Angabe der Fremdschlüsselbeziehung zwingend ist. Sie wird über eine Referenz auf eine Zeile der Mastertabelle spezifiziert. Die notwendigen Daten besorgt die Fill-Methode des CategoriesTableAdapters. Das folgende Codefragment zeigt beide Arten, eine Zeile hinzuzufügen:
'...\ADO\DataSetTypisiert\Hinzufuegen.vb |
Option Strict On
Imports System.Data.Common, System.Data.SqlClient
Namespace ADO
Module Hinzufuegen
Sub Test()
Dim nw As New NWDataSet()
'nw.Products.AddProductsRow(nw.Products.NewProductsRow())
Dim row As NWDataSet.ProductsRow = nw.Products.NewProductsRow()
row.ProductName = "Brie de Meaux"
row.UnitPrice = 3.1D
nw.Products.AddProductsRow(row)
Dim nwa As New NWDataSetTableAdapters.CategoriesTableAdapter()
nwa.Fill(nw.Categories)
nw.Products.AddProductsRow("Bordeaux", nw.Categories(0), 12D)
For Each z As NWDataSet.ProductsRow In nw.Products
Console.WriteLine("{0}: {1} Euro", z.ProductName, z.UnitPrice)
Next
Console.ReadLine()
End Sub
End Module
End Namespace
Hinweis |
Die auskommentierte Zeile würde aufgrund unbelegter Spaltenwerte einen Laufzeitfehler erzeugen. |
Beide Zeilen wurden dem DataSet hinzugefügt.
Brie de Meaux: 3.1 Euro
Bordeaux: 12 Euro
28.3.3 Datenzeilen bearbeiten 

Das Ändern von Datenzeilen erfolgt analog zum nicht-typisierten DataSet. Auch im typisierten Fall hier stehen Ihnen die Methoden BeginEdit, EndEdit und CancelEdit zur Verfügung. Diese Methoden sind optional; das folgende Codefragment nutzt sie:
'...\ADO\DataSetTypisiert\Bearbeiten.vb |
Option Strict On
Imports System.Data.Common, System.Data.SqlClient
Namespace ADO
Module Bearbeiten
Sub Test()
Dim nw As New NWDataSet()
Dim nwa As New NWDataSetTableAdapters.ProductsTableAdapter()
nwa.Fill(nw.Products)
Dim z As NWDataSet.ProductsRow = nw.Products(0)
z.BeginEdit()
Console.Write("Name für Chai: ")
z.ProductName = Console.ReadLine()
If z.ProductName.Equals("Tee") Then z.EndEdit() Else z.CancelEdit()
Console.WriteLine("{0}: {1} Euro", z.ProductName, z.UnitPrice)
Console.ReadLine()
End Sub
End Module
End Namespace
28.3.4 Datenzeilen suchen 

Die Tabellen eines typisierten DataSets stellen Find-Methoden zur Verfügung, die eine Zeile mit einem bestimmten Primärschlüssel suchen. In der typisierten Products-Tabelle heißt die Methode FindByProductID, in der typisierten Categories-Tabelle heißt sie FindByCategoryID.
'...\ADO\DataSetTypisiert\Suchen.vb |
Option Strict On
Imports System.Data.Common, System.Data.SqlClient
Namespace ADO
Module Suchen
Sub Test()
Dim nw As New NWDataSet()
Dim nwa As New NWDataSetTableAdapters.ProductsTableAdapter()
nwa.Fill(nw.Products)
With nw.Products.FindByProductID(3)
Console.WriteLine("{0}: {1}", .ProductID, .ProductName)
End With
Console.ReadLine()
End Sub
End Module
End Namespace
Handelt es sich um einen kombinierten Primärschlüssel aus mehreren Spalten, wie beispielsweise in der Tabelle Order Details, dann werden in den Bezeichner der Find-Methode die Namen der Spalten übernommen, die den Primärschlüssel bilden. In dieser Reihenfolge geben Sie auch die Werte für die Spalten in der Argumentenliste an.
28.3.5 Spalten mit Null-Wert 

Leider ist die Berücksichtigung von Nullwerten im typisierten DataSet recht unglücklich. Anstatt in den Get- und Set-Methoden der Eigenschaften, die die Spalten repräsentieren, den Wert Nothing auf DBNull abzubilden oder den Datentyp der Spalten als Nullable<Typ> zu definieren, gibt es Methoden zum Setzen von und Prüfen auf Nullwerte:
Sub Set<Spalte>Null() |
Im folgenden Beispiel werden alle Preise unter einem Schwellenwert mit SetUnitPriceNull() auf NULL gesetzt, und mit Write() wird nach dem alten Wert (DataRowVersion.Original) mittels IsUnitPriceNull() ausgegeben, ob der Wert ein Nullwert ist.
'...\ADO\DataSetTypisiert\Null.vb |
Option Strict On
Imports System.Data.Common, System.Data.SqlClient
Namespace ADO
Module Null
Sub Test()
Dim nw As New NWDataSet()
Dim nwa As New NWDataSetTableAdapters.ProductsTableAdapter()
nwa.Fill(nw.Products)
For Each zeile As NWDataSet.ProductsRow In nw.Products
If zeile.UnitPrice < 20 Then zeile.SetUnitPriceNull()
Console.Write("{0} -> {1} ", _
zeile("UnitPrice", DataRowVersion.Original), _
If(zeile.IsUnitPriceNull(), "NULL", zeile.UnitPrice.ToString()))
Next
Console.ReadLine()
End Sub
End Module
End Namespace
Alle Preise unter 20 sind nun Nullwerte:
18.0000 -> NULL 19.0000 -> NULL 10.0000 -> NULL 22.0000 -> 22.0000 ...
28.3.6 Tabellenbeziehungen 

Jede Zeile kann auf Spalten einer Fremdschlüsselbeziehung typrichtig zugreifen:
Property <Mastertabelle>Row As <Mastertabelle>Row |
Die entsprechenden Funktionen in einem untypisierten DataSet sind GetParentRow sowie GetChildRows, denen Sie aber noch explizit die Beziehung angeben müssen, die verwendet werden soll. Diese Information wurde vom Designer automatisch im typisierten DataSet abgelegt und in der grafischen Darstellung kenntlich gemacht (siehe Abbildung 28.3). Meiner Meinung nach wären entweder zwei schreibgeschützte Eigenschaften oder zwei Methoden besser als die Kombination aus einer änderbaren Eigenschaft und einer Funktion.
Im folgenden Beispiel wird zu jeder Zeile der Detailtabelle Products mit CategoriesRow die entsprechende Zeile der Mastertabelle Categories ermittelt, und zu jeder Zeile der Mastertabelle werden mit GetProductsRows() alle Zeilen in der Detailtabelle ermittelt, die sich auf diese Zeile beziehen. Da Daten beider Tabellen benötigt werden, müssen auch beide befüllt werden. Die innere Iteration der zweiten Auflistung können Sie auch mit einer gewöhnlichen Schleife realisieren.
'...\ADO\DataSetTypisiert\Beziehungen.vb |
Option Strict On
Imports System.Data.Common, System.Data.SqlClient
Namespace ADO
Module Beziehungen
Sub Print(ByVal row As NWDataSet.ProductsRow)
Console.Write("{0} ", row.ProductName)
End Sub
Sub Test()
Dim nw As New NWDataSet()
Dim pa As New NWDataSetTableAdapters.ProductsTableAdapter()
pa.Fill(nw.Products)
Dim ca As New NWDataSetTableAdapters.CategoriesTableAdapter()
ca.Fill(nw.Categories)
For Each detail As NWDataSet.ProductsRow In nw.Products
Console.WriteLine("Prudukt {0} referenziert {1} ", _
detail.ProductName, detail.CategoriesRow.CategoryName)
Next
For Each master As NWDataSet.CategoriesRow In nw.Categories
Console.Write("{0} wird referenziert von ", master.CategoryName)
Array.ForEach(master.GetProductsRows(), AddressOf Print)
Console.WriteLine()
Next
Console.ReadLine()
End Sub
End Module
End Namespace
Es gibt jeweils eine Elternzeile, jedoch null oder mehr Kindzeilen:
Produkt "Chai" referenziert Beverages
...
Produkt "Lakkalikööri" referenziert Beverages
Produkt "Original Frankfurter grüne Soße" referenziert Condiments
Beverages wird referenziert von "Chai" "Chang" "Guaraná Fantástica"
"Sasquatch Ale" "Steeleye Stout" "Côte de Blaye" "Chartreuse verte"
"Ipoh Coffee" "Laughing Lumberjack Lager" "Outback Lager"
"Rhönbräu Klosterbier" "Lakkalikööri"
Condiments wird referenziert von "Aniseed Syrup"
"Chef Anton's Cajun Seasoning" "Chef Anton's Gumbo Mix"
"Grandma's Boysenberry Spread" "Northwoods Cranberry Sauce" "Genen Shouyu"
"Gula Malacca" "Sirop d'érable" "Vegie-spread"
"Louisiana Fiery Hot Pepper Sauce" "Louisiana Hot Spiced Okra"
"Original Frankfurter grüne Soße"
...
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.