Free Trial

Safari Books Online is a digital library providing on-demand subscription access to thousands of learning resources.


  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • DownloadDownload
  • PrintPrint
Share this Page URL
Help

4. Einführung ADO.NET > Das Command-Objekt

Das Command-Objekt

An Abfragen aller Art (SQL-Queries, Stored Procedures) führt beim Programmieren von Datenbankanwendungen kein Weg vorbei. Unter ADO.NET werden für alle Datenbankabfragen Command-Objekte benutzt, die zentraler Bestandteil der jeweiligen .NET-Datenprovider sind.

Erzeugen und Anwenden eines Command-Objekts

Wie bei fast allen anderen ADO.NET-Objekten, bieten sich auch zum Erzeugen eines Command-Objekts verschiedene Konstruktoren an. Eine übliche Vorgehensweise ist es, die gewünschte Abfrage neben dem zuvor angelegten Connection-Objekt an den Konstruktor der Klasse zu übergeben:

Dim cmd As New Command(sql As String, conn As Connection)

Das so erzeugte und initialisierte Command-Objekt kann dann z.B. an den Konstruktor der DataAdapter-Klasse weitergereicht werden, um letztendlich ein DataSet zu füllen.

Aber es geht auch ohne DataAdapter und DataSet, denn um SQL-Anweisungen direkt gegen die Datenquelle zu fahren, kann eine der Execute-Methoden (ExecuteNonQuery, ExecuteReader, ExecuteScalar) aufgerufen werden.

Beispiel

Es werden zwei OleDbCommand-Objekte erstellt. Mit dem ersten werden die Namen der Firmen aller Pariser Kunden aus Nordwind.mdb geändert, mit dem zweiten wird ein DataAdapter erstellt, der zum Befüllen eines DataSet-Objekts mit den Kunden-Datensätzen dient.

Dim conn As New OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0; Data Source=Nordwind.mdb;")

Dim updCmd As New OleDbCommand("UPDATE Kunden SET Firma = 'Pariser Kunde' WHERE Ort = 'Paris'", conn)

Dim selCmd As New OleDbCommand("SELECT Firma, Ort FROM Kunden WHERE Ort = 'Paris'", conn)

Dim da As New OleDbDataAdapter(selCmd)
Dim ds As New DataSet()
conn.Open()

UPDATE-Befehl wird gegen die Datenbank gefahren:

updCmd.ExecuteNonQuery()

DataSet erhält neue Tabelle (»PariserKunden«) mit Datensätzen gemäß SELECT-Befehl:

da.Fill(ds, "PariserKunden")
conn.Close()

Hinweis

Den vollständigen Code finden Sie im How-to 4.3 »... eine Aktionsabfrage ausführen?«.

Erzeugen mittels CreateCommand-Methode

Auch mit Hilfe der CreateCommand-Methode eines Connection-Objekts können Sie ein Command-Objekt erzeugen. Damit ersparen Sie sich etwas Schreibarbeit.

Beispiel

Zwei äquivalente Varianten, wenn ein gültiges Connection-Objekt conn vorliegt.

Variante A:

Dim cmd As New OleDbCommand()
cmd.Connection = conn

Variante B:

Dim cmd As OleDbCommand = conn.CreateCommand()

Eigenschaften des Command-Objekts

Wir werden uns hier nur auf eine knappe Darstellung der wichtigsten Eigenschaften beschränken.

Connection- und CommandText-Eigenschaft

Beide Eigenschaften werden üblicherweise bereits im Konstruktor übergeben (siehe oben), man kann Sie aber auch separat zuweisen.

Beispiel

Zwei Varianten zum Erzeugen und Initialisieren eines OleDbCommand-Objekts.

Dim cmd As New OleDbCommand("UPDATE Kunden SET Firma = 'Pariser Firma' WHERE Ort = 'Paris'", conn)

ist äquivalent zu

Dim cmd As New OleDbCommand()
cmd.Connection = conn
cmd.CommandText = "UPDATE Kunden SET Firma = 'Pariser Firma' WHERE Ort = 'Paris'"

CommandTimeout-Eigenschaft

Um festzulegen, wie lange die Ausführung einer Abfrage maximal dauern darf, können Sie der Command-Timeout-Eigenschaft einen Wert in Sekunden zuweisen (Standardwert = 30 Sekunden).

Beispiel

Ein DataSet wird mit der Kundenliste der SQL-Datenbank Northwind gefüllt, wofür maximal 10 Sekunden zur Verfügung stehen.

Dim conn As New SqlConnection(
                         "Data Source=(local);Integrated Security=sspi;Initial Catalog=Northwind")
Dim cmd As New SqlCommand("SELECT CustomerID, CompanyName FROM Customers", conn)

Die Ausführung der Abfrage darf maximal 30 Sekunden dauern:

cmd.CommandTimeout = 30
Dim da As New SqlDataAdapter()
da.SelectCommand = cmd
Dim ds As New DataSet()
conn.Open()
da.Fill(ds, "Kunden")
conn.Close()

Hinweis

Sollte eine Abfrage dennoch zu lange dauern, so können Sie diese innerhalb einer asynchronen Umgebung mit Hilfe der Cancel-Methode abbrechen.

Zum Ausführen einfacher Datenbankabfragen (wie im obigen Beispiel), können Sie auf das explizite Erzeugen eines Command-Objekts verzichten, denn man kann den SQL-String auch direkt dem DataAdapter als Parameter übergeben.

Beispiel

Eine gleichwertige Realisierung des Vorgängerbeispiels.

Dim da As New SqlDataAdapter("SELECT CustomerID, CompanyName FROM Customers", conn)
da.SelectCommand.CommandTimeout = 30

CommandType-Eigenschaft

Mit der CommandType-Eigenschaft definieren Sie die auszuführende Operation. Mittels der gleichnamigen Enumeration stehen drei Möglichkeiten zur Verfügung:

  • Text (Standardwert)

    Hier können Sie eine frei definierbare SQL-Abfrage übergeben

  • StoredProcedure

    Hier soll eine in der Datenbank gespeicherte Prozedur bzw. Auswahlabfrage aufgerufen werden

  • TableDirect

    Hier wird direkt der Name einer Tabelle angegeben (entspricht SELECT * FROM <Tabellenname> )

Beispiel

Aufruf der Stored Procedure »Sales by Years« in der Datenbank Northwind.

Dim cmd As New SqlCommand("Sales by Year", conn)
cmd.CommandType = CommandType.StoredProcedure
Dim parm1 As New SqlParameter("@Beginning_Date", SqlDbType.DateTime)

Definition als Input-Parameter:

parm1.Direction = ParameterDirection.Input

Das Beginn-Datum wird der ersten TextBox entnommen:

parm1.Value = Convert.ToDateTime(TextBox1.Text)

Parameter hinzufügen:

cmd.Parameters.Add(parm1)

Hinweis

Den kompletten Code finden Sie im How-to 14.5 »... eine Gespeicherte Prozedur aufrufen?«. Der nach dem gleichen Prinzip funktionierende Aufruf einer in der Datenbank Nordwind.mdb gespeicherten Auswahlabfrage ist im How-to 4.4 »...eine Access-Auswahlabfrage aufrufen?« erklärt.

UpdatedRowSource-Eigenschaft

Diese Eigenschaft dürfte für den Einsteiger zunächst nur von untergeordnetem Interesse sein. Der Profi weiß aber, dass man mit UPDATE- und INSERT-Abfragen nicht nur Datensätze in der Datenquelle ändert, sondern dass auch Ausgabeparameter oder sogar Datensätze zurückgegeben werden können.

Typisch ist dies bei so genannten Stapel- bzw. Batch-Abfragen, denn hier können Sie z.B. Ausgabeparameter bzw. Datensätze aus der Datenbank abrufen, sofort nachdem der DataAdapter eine Aktualisierung entsprechend seiner UpdateCommand- oder InsertCommand-Eigenschaft durchgeführt hat.

Mittels der UpdatedRowSource-Eigenschaft legen Sie fest, ob und wie das Command-Objekt die von der Datenquelle zurückgelieferten Parameter bzw. Zeilen in das DataSet-Objekt einfügen soll.

Die UpdateRowSource-Enumeration stellt dazu entsprechende Konstanten bereit:

Tabelle 4.7 Die Mitglieder der UpdatedRowSource-Enumeration

UpdatedRowSource-Mitglied

Beschreibung

Both

Sowohl die erste zurückgegebene Zeile als auch die Ausgabeparameter werden der geänderten Zeile im DataSet zugeordnet (Standard)

FirstReturnedRecord

Nur die Daten in der ersten zurückgegebenen Zeile werden der geänderten Zeile im DataSet zugeordnet

OutputParameters

Nur die Ausgabeparameter werden der geänderten Zeile im DataSet zugeordnet

None

Alle zurückgegebenen Parameter oder Zeilen werden ignoriert

Beispiel

Eine Batch-Abfrage kapselt zwei SELECT-Anweisungen in einem String

Dim sqlBatch As String = "SELECT CustomerID, CompanyName, ContactName, ContactTitle " &
                         "FROM Customers WHERE CustomerID = 'ALFKI'; " &
                         "SELECT OrderID, OrderDate, RequiredDate, ShippedDate, Freight " &
                         "FROM Orders WHERE CustomerID = 'ALFKI'"

Dim cmd As New OleDbCommand(sqlBatch, conn)
cmd.UpdatedRowSource = UpdateRowSource.None
Dim da As New OleDbDataAdapter(cmd)
...

Hinweis

Das vollständige Beispiel finden Sie im How-to 14.7 »... mit Stapel-Abfragen arbeiten?«.

Methoden des Command-Objekts

ExecuteNonQuery-Methode

Diese Methode setzen Sie vor allem ein, um Aktionsbefehle auf Basis von UPDATE, INSERT oder DELETE direkt gegen die Datenbank auszuführen (also ohne Verwendung von DataAdapter und DataSet). Rückgabewert ist hier die Anzahl der betroffenen Datensätze (sonst –1).

Beispiel

Ein OleDbCommand-Objekt wird erzeugt und eine UPDATE-Anweisung gegen die Datenbank gefahren. Die Anzahl betroffener Datensätze wird angezeigt (ein gültiges OleDbConnection-Objekt conn wird vorausgesetzt).

Dim updStr As String = "UPDATE Kunden SET Firma = 'Pariser Firma' WHERE Ort = 'Paris'"
Dim updCmd As New OleDbCommand(updStr, conn)
conn.Open()

SQL-Anweisung ausführen und Anzahl betroffener Datensätze anzeigen:

Label1.Text = cmd.ExecuteNonQuery.ToString()

Hinweis

Das ausführliche Beispiel findet sich im How-to 4.2 »... eine Aktionsabfrage ausführen?«.

Weitere Möglichkeiten für Aktionsbefehle sind die Abfrage der Struktur einer Datenbank oder das Erstellen von Datenbankobjekten wie z.B. Tabellen (CREATE TABLE ...).

ExecuteReader-Methode

Auf Basis eines SELECT-Befehls erzeugt diese Methode ein DataReader-Objekt. Ein Instanziieren des Data-Readers mittels New-Konstruktor entfällt deshalb.

Beispiel

Auf Basis eines gültigen OleDbConnection-Objekts und eines SELECT-Befehls wird ein OleDbCommand-Objekt erstellt und zum Erzeugen eines DataReader-Objekts verwendet.

Dim selStr As String = "SELECT Firma, Kontaktperson, Ort FROM Kunden WHERE Ort = 'Paris'"
Dim selCmd As New OleDbCommand(selStr, conn)
conn.Open()
Dim dr As OleDbDataReader = selCmd.ExecuteReader(CommandBehavior.CloseConnection)

Hinweis

Mehr erfahren Sie im DataReader-Abschnitt dieses Kapitels bzw. im How-to 6.10 »... mit DataReader und ListView arbeiten?«.

ExecuteScalar-Methode

Rückgabewert dieser Methode ist das Objekt der ersten Spalte der ersten Zeile aus der Menge der zurückgegebenen Datensätze.

Generell eignet sich die ExecuteScalar-Methode des Command-Objekts für alle Abfragen, bei denen man nur an der Rückgabe eines einzigen Wertes interessiert ist.

Beispiel

Abfrage des Firmennamens eines bestimmten Kunden.

Dim cmd As New SqlCommand("SELECT Firma FROM Kunden WHERE KundenCode = 'ALFKI'", conn)
conn.Open()
Label1.Text = Convert.ToString(cmd.ExecuteScalar)

Besonders vorteilhaft kann man ExecuteScalar zur Ausführung von Aggregatfunktionen verwenden, was weniger Aufwand erfordert als die Anwendung der ExecuteReader-Methode.

Beispiel

Aus der Datenbank Northwind wird die Anzahl der in Paris wohnhaften Kunden abgefragt und angezeigt.

Dim cmd As New SqlCommand()
cmd.Connection = conn
cmd.CommandText = "SELECT COUNT(*) AS Anzahl FROM Customers WHERE City = 'Paris'"
cmd.Connection.Open()                                  ' oder auch: conn.Open()
Label1.Text = cmd.ExecuteScalar().ToString()
cmd.Connection.Close()

Freigabe von Connection- und Command-Objekten

In einfachen Codebeispielen stellt man häufig fest, dass der Aufruf der Dispose()-Methode auf SqlConnection- und SqlCommand-Objekten fehlt[26]. Auch wird der Datenzugriffscode meist nicht in Try-Finally-Blöcke eingerahmt.

Beispiel

Die (leider nicht ganz saubere) Programmierung einer Datenbankverbindung

Dim conn As New SqlConnection(connString)
Dim cmd As New SqlCommand(cmdString, conn)
conn.Open()
cmd.ExecuteNonQuery()
conn.Close()

Das Problem ist, dass SqlConnection und SqlCommand die Schnittstelle IDisposable implementieren, d.h., es können auch Ressourcen aus nicht verwaltetem (unmanaged) Code zu bereinigen sein. Als Programmierer müssen Sie dann unter allen Umständen absichern, dass Dispose auf diesen Objekten aufgerufen wird, nachdem die Arbeit mit ihnen beendet ist. Weil bei Nichtverfügbarkeit der Datenbank immer ein Fehler auftreten kann, sollten Sie den Aufruf von Dispose auch für diesen Fall gewährleisten.

Das Problem lässt sich elegant mittels Using-Schlüsselwort lösen, welches Ihnen lästige Schreibarbeiten abnimmt, denn intern wird automatisch ein Try-Finally-Block um das entsprechende Objekt generiert und beim Beenden wird für das Objekt Dispose aufgerufen.

Beispiel

Saubere Programmierung des Vorgängerbeispiels

Using conn As New SqlConnection(connString)
   Using cmd As New SqlCommand(cmdString, conn)
      conn.Open()
      cmd.ExecuteNonQuery()
   End Using
End Using

Der intern generierte Code für obige Zeilen könnte etwa folgendermaßen aussehen:

Dim conn As SqlConnection = Nothing
Dim cmd As SqlCommand = Nothing
Try
    conn = New SqlConnection(connString)
    cmd = New SqlCommand(cmdString, conn)
    conn.Open()
    cmd.ExecuteNonQuery()
Finally
    If cmd IsNot Nothing Then cmd.Dispose()
    If conn IsNot Nothing Then conn.Dispose()
End Try

Hinweis

Falls Sie, wie im obigen Beispiel, den Aufruf von Close für die SqlConnection vermissen, seien Sie trotzdem unbesorgt: Intern überprüft Dispose den Status der Verbindung und schließt diese für Sie.



[26] Auch die Codebeispiele dieses Buchs bilden da (aus Platzgründen!) keine Ausnahme.

  • Safari Books Online
  • Create BookmarkCreate Bookmark
  • Create Note or TagCreate Note or Tag
  • DownloadDownload
  • PrintPrint