12.5 SqlDataReader und OleDbDataReader
 
Die Reader-Klassen SqlDataReader und OleDbDataReader liefern einen Strom von Datenbankzeilen, den Sie vorwärts gerichtet durchlaufen können. Sie sollten auch wissen, was Sie mit den Reader-Objekten nicht machen können:
|
Sie können einen bestimmten Datensatz nicht gezielt anspringen. |
|
Sie können die Ergebnismenge nicht rückwärts durchlaufen. |
|
Sie können die Daten in der Datenbank nicht ändern. |
Sie können lediglich das Ergebnis von vorn bis hinten lesen und die Daten dabei beispielsweise in irgendeiner Form ausgeben. Für alle Aufgaben, bei denen das nicht reicht, müssen Sie die DataSet-Klasse verwenden, die in Abschnitt 12.6, die DataSet-Klasse, vorgestellt wird. Der Vorteil dieser vergleichsweise »dummen« Reader-Klassen liegt in ihrer Effizienz. Diese Klassen können nicht viel. Aber das Wenige, was sie können, nämlich Daten aus einer Datenbank auslesen, wird oft benötigt. Deswegen gibt es diese entsprechend spezialisierten und optimierten Klassen.
12.5.1 Ein Reader-Objekt an ein Steuerelement binden
 
Das Skript db_01.aspx in Abschnitt 12.1, Auf Datenbanken zugreifen – ein Crashkurs, hat bereits einen einfachen und zugleich sehr effizienten Umgang mit dem OleDbDataReader-Objekt demonstriert. Wenn Sie ein OleDbDataReader-Objekt an ein Listensteuerelement binden, müssen Sie sich nicht mehr um die Details der Darstellung kümmern. In db_01.aspx übernimmt die Zeile myGrid.DataSource = myDataReader die Datenbindung. Hier noch einmal im Zusammenhang:
' ...
' SQL-Kommando erstellen und ausführen
Dim sql As String
sql = "SELECT * FROM Versandfirmen"
Dim cmd As New OleDbCommand(sql, conn)
Dim myDataReader As OleDbDataReader
myDataReader = cmd.ExecuteReader()
' SQL-Resultat an ein Steuerelement binden
myGrid.DataSource = myDataReader
DataBind()
' ...
12.5.2 Ein Reader-Objekt an ein Listensteuerelement binden
 
Für die gezielte Verwendung von Daten innerhalb eines Formulars können Sie statt einem DataGrid-Steuerelement auch ein Listensteuerelement verwenden. In einer Anwendung möchten Sie den Benutzer beispielsweise fragen, mit welchem Paketdienst seine Waren verschickt werden sollen. Der Anwender trifft seine Auswahl anhand von Optionsfeldern. db_05a.aspx enthält den erforderlichen Code und Abbildung 12.8 zeigt die Darstellung im Browser.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 12.8 Auch Listensteuerelemente lassen sich an Datenquellen binden.
<!-- db_05a.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
If IsPostBack Then
ausgabe.innerText = "Ihre Auswahl: "
ausgabe.innerText &= Versender.SelectedItem.Text
Else
' Verbindungszeichenfolge zusammensetzen
Dim connStr As String
connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
connStr += "Data Source=" _
& "C:\ASPdotNETBuch\Listings\Nordwind.mdb;"
' Verbindung zur Datenbank herstellen
Dim conn As New OleDbConnection(connStr)
conn.Open()
' SQL-Kommando erstellen und ausführen
Dim sql As String
sql = "SELECT * FROM Versandfirmen"
Dim cmd As New OleDbCommand(sql, conn)
Dim myDataReader As OleDbDataReader
myDataReader = cmd.ExecuteReader()
' SQL-Resultat an ein Steuerelement binden
'myGrid.DataSource = myDataReader
Versender.DataSource = myDataReader
Versender.DataValueField="Firmen-Nr"
Versender.DataTextField="Firma"
Versender.DataBind()
myDataReader.Close()
conn.Close()
End If
End Sub
</script>
<html><head><title>
DataValueField und DataTextField bei einem
Listensteuerelement nutzen
</title></head>
<body>
<h3>DataValueField und DataTextField bei einem
Listensteuerelement nutzen</h3>
<p>Mit welchem Paketdienst soll Ihre Ware
verschickt werden?</p>
<form runat="server">
<asp:RadioButtonList runat="server" id="Versender" />
<br>
<input type="submit" value=" OK " />
<p id="ausgabe" runat="server" />
</form>
</body></html>
Wenn der Anwender eine Auswahl trifft, wird unterhalb des Formulars der gewählte Paketdienst angezeigt. Im HTML-Teil von db_05a.aspx platzieren Sie ein asp:RadioButtonList-Element mit dem id-Attribut Versender. Die Prozedur Page_Load enthält zwei Zweige. Beim ersten Laden der Seite werden die Daten für das RadioButtonList-Steuerelement zusammengetragen. Der Code ist bis zur Zeile myDataReader = cmd.ExecuteReader() identisch mit dem bisherigen Vorgehen. Anschließend wird nicht myGrid, sondern Versender mit Daten bestückt. Dafür sorgen diese vier Zeilen:
Versender.DataSource = myDataReader
Versender.DataValueField="Firmen-Nr"
Versender.DataTextField="Firma"
Versender.DataBind()
Die Zuweisung an Versender.DataSource entspricht der bisherigen Zuweisung an myGrid.DataSource. Die Zuweisungen an DataValueField und DataTextField legen noch genauer fest, welche Daten wohin kommen. DataValueField nennt die Spalte für das value-Attribut des Optionsfeldes und DataTextField nennt die Spalte für die Beschriftung des Optionsfeldes. Ein Blick auf den generierten HTML-Code verdeutlicht die Arbeitsweise.
<input id="Versender_4" type="radio" name="Versender" value="3" checked="checked" />
<label for="Versender_4">Federal Shippings</label>
Der Versender mit der Firmen-Nr. 3 (value="3") heißt Federal Shippings.
12.5.3 Ein Reader-Objekt zeilenweise auswerten
 
Sie können die Abfrageergebnisse aber auch Zeile für Zeile und Spalte für Spalte selbst auswerten. db_06.aspx demonstriert, wie Sie mit Hilfe der Read()-Methode alle Zeilen der Ergebnismenge schrittweise durchlaufen können.
| Tipp Der Datensatzzeiger steht vor dem ersten Aufruf von Read() vor dem ersten Datensatz. Also können Sie mit While myReader.Read() bequem alle Datensätze durchlaufen.
|
Die Prozedur verwendet die Methode GetString(), um den Inhalt der Tabellenzeile auszulesen. Als Parameter übergeben Sie der Methode GetString() die Ordinalzahl der gewünschten Spalte zur Basis 0. Mit myString = myReader.GetString(1) lesen Sie den Inhalt der zweiten Spalte in die String-Variable myString ein. Die Voraussetzung für die Verwendung von GetString() ist übrigens, dass die Datenbankspalte selbst auch vom Typ String sein muss. Für andere Datentypen stellt die Klasse OleDbDataReader weitere Methoden wie GetInt32(), GetDouble(), GetDateTime() oder das universal verwendbare GetValue() zur Verfügung. Abbildung 12.9 zeigt das Ergebnis im Browser.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 12.9 Mit der Read()-Methode durchlaufen Sie schrittweise alle Datensätze.
<!-- db_06.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
' Verbindungszeichenfolge zusammensetzen
Dim connStr As String
connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
connStr += _
"Data Source=E:\ASPdotNETBuch\Listings\Nordwind.mdb;"
' Verbindung zur Datenbank herstellen
Dim conn As New OleDbConnection(connStr)
conn.Open()
' SQL-Kommando erstellen und ausführen
Dim sql As String
sql = "SELECT * FROM Versandfirmen"
Dim cmd As New OleDbCommand(sql, conn)
Dim myReader As OleDbDataReader
myReader = cmd.ExecuteReader()
Dim sb As New StringBuilder()
sb.Append ("Unsere Versandfirmen: <ul>")
' Die Ergebnisse des Reader-Objekts manuell
' verarbeiten
While myReader.Read()
sb.Append ("<li>")
sb.Append (myReader.GetString(1))
End While
sb.Append ("</ul>")
ausgabe.innerHtml = sb.toString()
myReader.Close()
conn.Close()
End Sub
</script>
<html><head><title>
Das OleDbDataReader-Objekt verwenden
</title></head>
<body>
<h3>Das OleDbDataReader-Objekt verwenden</h3>
<p runat="server" id="ausgabe" />
</body></html>
Die Routine setzt beim Durchlaufen der While-Schleife im StringBuilder-Objekt den HTML-Code zusammen. Der Ausdruck myReader.GetString(1) gibt jeweils den Inhalt der zweiten Spalte als String-Objekt zurück.
| Achtung Diese Schleife funktioniert nur dann problemlos, wenn die Spalte mit den Firmennamen auch stets einen Eintrag enthält. Bei einem leeren Feld tritt ein Fehler auf.
|
Den Fall können Sie testen, indem Sie in der von Ihnen verwendeten Nordwind-Datenbank einen Datensatz mit einer weiteren Versandfirma hinzufügen und dabei das Feld Firma leer lassen. Setzen Sie vorher in der Nordwind-Datenbank in der Entwurfsansicht für die Tabelle Versandfirmen für das Feld Firma die Eigenschaft Eingabe erforderlich auf Nein.
Wenn Sie einen Datensatz mit leerem Firmennamen hinzugefügt haben, generiert die Seite beim erneuten Aufruf diese Fehlermeldung:
Die angegebene Umwandlung ist ungültig
Auslöser ist die Zeile
sb.Append (myReader.GetString(1))
Die Umwandlung eines leeren Feldes in einen String scheitert. Für solche Fälle sollten Sie mit der Methode IsDBNull() zunächst überprüfen, ob die Spalte leer ist. Damit erhält die Schleife diese Form (db_06a.aspx):
While myReader.Read()
If Not myReader.IsDBNull(1) Then
sb.Append ("<li>")
sb.Append (myReader.GetString(1))
End If
End While
db_07.aspx demonstriert die Verwendung einiger weiterer Eigenschaften und Methoden der Reader-Klasse. Die Methode GetDataTypeName nennt den Datentyp, den die Datenbank verwendet. GetFieldType nennt den Datentyp, den .NET für das Feld vorgesehen hat. Da die Schleife, die die Tabellenspalten durchläuft, auf unterschiedliche Datentypen trifft, verwendet die Prozedur für das Auslesen die Methode GetValue() und konvertiert das zurückgegebene Objekt vom Typ Object anschließend mit toString() in einen String. Abbildung 12.10 zeigt die Darstellung von db_07.aspx im Browser.
 Hier klicken, um das Bild zu Vergrößern
Abbildung 12.10 GetDataTypeName nennt den Datentyp, den die Datenbank verwendet. GetFieldType nennt den .NET-Datentyp.
<!-- db_07.aspx -->
<%@ Page Language="VB" Debug="True" Strict="True" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.OleDb" %>
<script runat="server">
Sub Page_Load (ByVal Sender As Object, _
ByVal E As EventArgs)
' Verbindungszeichenfolge zusammensetzen
Dim connStr As String
connStr = "Provider=Microsoft.Jet.OLEDB.4.0;"
connStr += _
"Data Source=E:\ASPdotNETBuch\Listings\Nordwind.mdb;"
' Verbindung zur Datenbank herstellen
Dim conn As New OleDbConnection(connStr)
conn.Open()
' SQL-Kommando erstellen und ausführen
Dim sql As String
sql = "SELECT * FROM Versandfirmen"
Dim cmd As New OleDbCommand(sql, conn)
Dim myReader As OleDbDataReader
myReader = cmd.ExecuteReader()
Dim sb As New StringBuilder()
sb.Append ("Anzahl der Spalten: ")
sb.Append (myReader.FieldCount)
sb.Append ("<br><table border='1'>")
Dim i As Integer
' Die Namen der Spalten ermitteln
sb.Append ("<tr><td>Spaltennamen</td>")
For i = 0 to myReader.FieldCount -1
sb.Append ("<td>")
sb.Append (myReader.GetName(i))
sb.Append ("</td>")
Next
sb.Append ("</tr>")
' Datentyp mit GetDataTypeName
sb.Append ("<tr><td>Datentyp mit GetDataTypeName</td>")
For i = 0 to myReader.FieldCount -1
sb.Append ("<td>")
sb.Append (myReader.GetDataTypeName(i))
sb.Append ("</td>")
Next
sb.Append ("</tr>")
' Datentyp mit GetFieldType
sb.Append ("<tr><td>Datentyp mit GetFieldType</td>")
For i = 0 to myReader.FieldCount -1
sb.Append ("<td>")
sb.Append (myReader.GetFieldType(i))
sb.Append ("</td>")
Next
sb.Append ("</tr>")
' Die Tabellenzeilen auslesen
While myReader.Read()
sb.Append ("<tr><td></td>")
for i = 0 to myReader.FieldCount -1
If myReader.IsDBNull(i) Then
sb.Append ("<td></td>")
Else
sb.Append ("<td>")
sb.Append (myReader.GetValue(i).toString())
sb.Append ("</td>")
End If
Next
sb.Append ("</tr>")
End While
sb.Append ("</table>")
ausgabe.innerHtml = sb.toString()
myReader.Close()
conn.Close()
End Sub
</script>
<html><head><title>
Das OleDbDataReader-Objekt verwenden
</title></head>
<body>
<h3>Das OleDbDataReader-Objekt verwenden</h3>
<p id="ausgabe" runat="server" />
</body></html>
Die Klasse SqlDataReader funktioniert exakt genauso wie die Klasse OleDbDataReader. Sie fügt lediglich einige Methoden hinzu, die für die SQL-Server-typischen Datentypen optimiert sind, z. B. GetSqlDouble(), GetSqlString(), GetSqlInt32() usw.
Konstruktor: Sie erzeugen ein OleDbDataReader-Objekt über den Aufruf der ExecuteReader-Methode eines OleDbCommand-Objekts, z. B.:
myReader = myCommand.ExecuteReader()
|
| Eigenschaften
|
| Depth
|
Integer
|
Tiefe der Schachtelung für die aktuelle Zeile. Die äußerste Tabelle hat die Tiefe 0.
|
| FieldCount
|
Integer
|
Anzahl der Spalten in der aktuellen Zeile
|
| IsClosed
|
Boolean
|
True, wenn das Reader-Objekt geschlossen ist
|
Item(Integer)
oder
Item(String)
|
Object
|
Default-Eigenschaft. Der Wert der angegebenen Spalte. Sie geben entweder den Spaltennamen oder die Spaltenordnungszahl an.
|
| RecordsAffected
|
Integer
|
Die Anzahl der Zeilen, die von der ausgeführten SQL-Anweisung betroffen waren. Sollte erst nach dem Schließen des Reader-Objekts aufgerufen werden
|
| Methoden
|
| Close()
|
|
Schließt das Objekt
|
GetBoolean
(Integer)
|
Boolean
|
Gibt den Wert der angegebenen Spalte (nullbasiert) als logischen Wert an. Die Spalte muss bereits über ein logisches Format verfügen. Es werden keine Konvertierungen ausgeführt.
Für alle Get...-Methoden gilt: Vor Aufruf der Methode sollte mit IsDBNull überprüft werden, ob NULL-Werte vorhanden sind.
|
GetByte
(Integer)
|
Byte
|
Der Wert der Spalte als einzelnes Byte
|
| GetBytes(...)
|
Long
|
Liest beginnend am angegebenen Pufferoffset einen Stream von Bytes aus dem angegebenen Spaltenoffset als Array in den Puffer
|
| GetChar(Integer)
|
Char
|
Wert der Spalte als Char-Objekt
|
| GetChars(...)
|
Long
|
Liest beginnend am angegebenen Pufferoffset einen Stream von Zeichen aus dem angegebenen Spaltenoffset in den Puffer eines Arrays
|
| GetDataTypeName(Integer)
|
String
|
Name des Quelldatentyps
|
| GetDateTime(Integer)
|
DateTime
|
Wert der Spalte als DateTime-Objekt
|
GetDecimal
(Integer)
|
Decimal
|
Wert der Spalte als Decimal-Objekt
|
GetDouble
(Integer)
|
Double
|
Wert der Spalte als Typ Double
|
GetFieldType
(Integer)
|
Type
|
Der Typ, der den Datentyp des Objekts darstellt
|
| GetFloat(Integer)
|
Single
|
Wert der Spalte als Gleitkommazahl einfacher Genauigkeit
|
| GetGuid(Integer)
|
Guid
|
Wert der Spalte als GUID (Globally Unique Identifier)
|
| GetInt16(Integer)
|
Short
|
Wert der Spalte als 16-Bit-Ganzzahl mit Vorzeichen
|
| GetInt32(Integer)
|
Integer
|
Wert der Spalte als 32-Bit-Ganzzahl mit Vorzeichen
|
| GetInt64(Integer)
|
Long
|
Wert der Spalte als 64-Bit-Ganzzahl mit Vorzeichen
|
| GetName(Integer)
|
String
|
Der Name der Spalte
|
GetOrdinal
(String)
|
Integer
|
Nennt die zum Spaltennamen gehörige Ordinalzahl
|
| GetSchemaTable()
|
DataTable
|
Ein DataTable-Objekt, das die Spalten-Metadaten des OleDbDataReader-Objekts beschreibt
|
GetString
(Integer)
|
String
|
Wert der Spalte als String
|
| GetTimeSpan(Integer)
|
TimeSpan
|
Wert der Spalte als TimeSpan-Objekt
|
| GetValue(Integer)
|
Object
|
Wert der Spalte im systemeigenen Format
|
GetValues
(Object())
|
Integer
|
Alle Attributspalten der aktuellen Zeile
|
| IsDBNull(Integer)
|
Boolean
|
True, wenn die Spalte keinen Wert enthält
|
| NextResult()
|
Boolean
|
Setzt den Datenleser beim Lesen der Ergebnisse von SQL-Batchanweisungen auf das nächste Ergebnis
|
| Read()
|
Boolean
|
True, wenn weitere Datensätze vorhanden sind, sonst False (While myReader.Read() ...)
|
Tabelle 12.4 Steckbrief der Klasse OleDbDataReader
|