Die Community zu .NET und Classic VB.
Menü

Einstieg in ADO.NET

 von 

Übersicht 

ADO (ActiveX Data Objects) .NET und ADO Classic unterscheiden sich grundlegend, vorallem in der Art des Datenzugriffes. Wo bei ADO Classic lediglich ein RecordSet zur Verfügung gestellt wurde um Daten zu verwenden, bietet .NET doch gleich eine komplette Plattform. Die Überbleibsel von ADO Classic finden sich im Connection-Objekt und teilweise im Command-Objekt. Das war es dann aber auch schon.

Dieses Tutorial soll den Einstieg in ADO.NET etwas erleichtern.

Mit freundlichen Grüßen
Christian Dernehl ()

Viele für das Selbe - .NET Connectors  

Microsoft stellt direkt mit ADO.NET abstrakte Klassen bereit, die von Datenbanksoftwareunternehmen verwendet werden können um Entwicklern möglichst effektiv den Datenzugriff zu ermöglichen. Als Alternative werden außerdem noch ODBC und OLEDB angeboten. Unter einem .NET Connector versteht man in dieser Hinsicht meist eine Klassenbibliothek mit Klassen, die zur spezifischen Datenbank passen. Es gibt spezielle Treiber für fast alle Datenbanksysteme, daher werden hier nur die bekanntesten aufgelistet:

Jede Klassenbibliothek weicht ein wenig ab und hat auch die ein oder andere Spezialität. Daher wird in den folgenden Beispielen der OLEDB-Namespace verwendet.

Verbinden.... - Das Connection-Objekt  

Um Daten abzurufen, bzw. zu bearbeiten müssen Sie zunächst eine Verbindung zur Datenquelle herstellen. Diese Verbindung wird mithilfe des OleDBConnection-Objektes hergestellt. Das OleDBConnection-Objekt bietet u.A. die Methode "Open" und die Eigenschaft "ConnectionString". Die Eigenschaft "ConnectionString" enthält die zur Verbindung notwendige Zeichenfolge. Eine Liste von Verbindungszeichenfolgen finden Sie auf www.connectionstrings.com. Sie müssen notwendigerweise nicht die Verbindung öffnen; wenn Sie einen DataAdapter verwenden übernimmt dieser das Öffnen und Schließen der Verbindung. Sie sollten (wegen dem Traffic) und müssen die Verbindung nur bei folgenden Bedingungen öffnen:

  • Sie möchten einen einzelnen SQL-Befehl an die Datenquelle senden
  • Sie möchten einen DataReader verwenden

Sonst sollten Sie die Verbindung zur Datenquelle geschlossen halten. Microsoft ADO.NET unterstützt weiterhin auch Connection-Pooling. Wenn das Datenbanksystem, dass Sie verwenden Connection-Pooling unterstützt, dann wird ADO Connection-Pooling für Sie übernehmen. Das bedeutet für Sie: Sie können sich ruhig erlauben einige Verbindungen zur Datenquelle zu verwenden.

Imports System
Imports System.Data.OleDB

Class Datenbeispiel

    Public Shared Sub Main()

        Dim myCon As New OleDbConnection
        Try

            'Setzt die Verbindungszeichenfolge
            myCon.ConnectionString = "Connectionzeichenfolge"
            'Öffnet die Verbindung
            myCon.Open()
            'Schließt die Verbindung
            myCon.Close()

        Catch ex As Exception
            Messagebox.Show("Fehler beim Verbinden!")
        End Try

    End Sub

End Class

Listing 1

Befehle an die Datenbank - Das Command-Objekt  

Um Befehle an die Datenbank zu senden gibt es das Command-Objekt. Das Command-Objekt erfordert eine offene Verbindung (im Zusammenhang mit dem DataAdapter jedoch nicht) und man kann Befehle an die Datenbank senden. Die wichtigsten Eigenschaften und Methoden sind:

CommandText: Enthält den SQL-Befehlstext oder den Namen der gespeicherten Abfrage.
CommandType: Wählbar zwischen Text, Stored Procedure (gespeicherte Abfrage) und TableDirect. Hierzu gilt:
Text: Reines SQL; Text ist standardmäßig gewählt.
Stored Procedure: Der CommandText enthält den Namen einer StoredProcedure.
TableDirect: Sollte nicht verwendet werden, da es kaum Kompatibilität außerhalb OLEDB gibt. TableDirect erfordert als CommandText eine oder mehrere Tabellennamen.
Connection: Die zu verwendende Verbindung für den Befehl.
ExecuteNonQuery: Führt den Befehl aus und gibt die Anzahl der betroffenden Datensätze zurück.
ExecuteReader: Gibt einen DataReader zurück.
ExecuteScalar: Gibt nur den ersten Eintrag des Ergebnisses zurück.
Parameters: Enthält Parameter für die Abfrage.

Es kann direkt SQL an die Datenquelle gesendet werden oder als Befehlstext der Name einer gespeicherten Prozedur angegeben werden. Sollte der Name einer gespeicherten Prozedur verwendet werden muss der CommandType "Stored Procedure" sein.

Sollten Sie Daten auswählen (Select) dann müssen Sie diesen Befehl mit einem DataReader oder DataAdapter verbinden (dazu später mehr).

Sie können auch Parameter verwenden um SQL-Injection vorzubeugen und Ihre Abfragen dynamischer zu machen. Im folgenden Beispiel werden Daten in eine Tabelle t_Example geschrieben.

Imports System
Imports System.Data.OleDB

Class Datenbeispiel

    Public Shared Sub Main()

        Dim myCon As New OleDbConnection
        Dim myCom As New OleDbCommand("INSERT INTO t_Example VALUES(?,?,?,?);", myCon)
        Try

            'Setzt die Verbindungszeichenfolge
            myCon.ConnectionString = "Connectionzeichenfolge"
            'Öffnet die Verbindung
            myCon.Open()
            Dim myp As New OleDBParameter
            myp.Value = "Hans"
            myp.OleDbType = OleDb.OleDbType.VarChar
            myp.Parametername = "?"
            myCom.Parameters.Add(myp)
            myCom.Parameters.Add("Mustermann")
            myCom.Parameters.Add("22")
            myCom.Parameters.Add("Verwaltung")
            myCom.ExecuteNonQuery()
            'Schließt die Verbindung
            myCon.Close()

        Catch ex As Exception

            Messagebox.Show("Fehler aufgetreten!")

        End Try

    End Sub

End Class

Listing 2

Nehmen im Schnelldurchlauf - Der DataReader  

Der DataAdapter stellt eine Verbindung zur Datenbank auf eine bessere Art und Weise her als der DataReader. Weiterhin kann der DataAdapter auch Daten in der Datenbank aktualisieren. Ein DataAdapter erfordert eine Verbindungsobjekt und ein Befehlsobjekt. Weiterhin ist eine DataTable, eine virtuelle Tabelle von Nöten. Jeder DataAdapter, sei es OleDb, sei es SQLClient, füllt einen DataTable. Dadurch können Daten aus verschiedenen Datenbanksystem entnommen werden, sofern dieses notwendig ist.

Das DataTable-Objekt ist genau so aufgebaut wie eine realle Tabelle. Es gibt Felder (Columns) und Datensätze (Rows). Über diese beiden Eigenschaften kann auf die Daten des DataTable-Objektes zugegriffen werden. Der DataAdapter kann entweder einem DataTable-Objekt nur das Schema, bzw. die Stuktur oder die Daten inklusive Struktur einfügen. Im folgenden Beispiel wird zunächst die Struktur in ein seperates DataTable-Objekt, dann die Daten inklusive Struktur in ein weiteres DataTable-Objekt geladen.

Imports System
Imports System.Data.OleDB

Class Datenbeispiel

    Public Shared Sub Main()

        Dim myCon As New OleDbConnection("Connectionzeichenfolge")
        Dim myCom As New OleDbCommand("SELECT * FROM t_Example;", myCon)
        Dim myAdapter As New OleDbDataAdapter(myCom)
        Dim myStruktur As New DataTable("Struktur")
        Dim myData As New DataTable("Data")
        Try

            'Struktur laden
            myAdapter.FillSchema(myStruktur, SchemaType.Mapped)

            'Daten und Struktur laden
            myAdapter.Fill(myData)

            'Daten im Debugfenster ausgeben
            For Each dr As DataRow In myData.Rows

                For Each dc As DataColumn In myData.Columns
                    Debug.Write(dr.Item(dc.Columnname).ToString() + (";"))
                Next
                Debug.WriteLine("")
            Next

        Catch ex As Exception
            Messagebox.Show("Fehler!")
        End Try

    End Sub

End Class

Listing 3

Daten modifizieren - DataTables II  

Im vorigen Kapitel wurde gezeigt, wie man Daten auslesen kann. Interessant ist jedoch vorallem das Ändern von Daten in einem DataTable-Objekt und in der Datenquelle. Zunächst müssen Sie jedoch die Daten im DataTable-Objekt ändern, die Aktualisierung ist im nächsten Teil beschrieben.

Sie können neue Datensätze anlegen mit der Methode "NewRow" des DataTable-Objektes. Das Löschen findet mit der Methode "Delete" statt. Die Änderung von Daten wird direkt über das DataRow-Objekt gemacht. Weiterhin gilt es zu verstehen, dass DataTable-Objekte völlig unabhängig von der Datenquelle sind. So können Sie z.B. DataTable-Objekte selber definieren, füllen und verwenden, ganz ohne Datenbank. Mit dem Framework 2.0 bzw. mit dem DataSet können Sie die Daten dann noch in XML speichern.

Im folgenden Beispiel wird ein DataTable-Objekt von Hand erstellt und ein weiteres von einer Datenquelle modifiziert.

Imports System
Imports System.Data
Imports System.Data.OleDB

Class Datenbeispiel

    Public Shared Sub Main()

        Dim myCon As New OleDbConnection("Connectionzeichenfolge")
        Dim myCom As New OleDbCommand("SELECT * FROM t_Example;", myCon)
        Dim myAdapter As New OleDbDataAdapter(myCom)
        Dim myDataTable As New DataTable("Self")
        Dim myDataSource As New DataTable("Data")
        Try

            'Daten laden
            myAdapter.Fill(myDataSource)

            'Neuen Datensatz anlegen
            Dim NewRecord As DataRow = myDataSource.NewRow()
            With NewRecord

                .Item("Feld1") = "Neuer Wert"
                .Item("Feld2") = "Neuer Wert für Feld 2"
                .Item("Feld3") = 5

            End With
            myDataSource.Rows.Add(NewRecord)

            'Den letzten Datensatz ändern
            Dim LastRec As DataRow = myDataSource.Rows(myDataSource.Rows.Count - 1)
            LastRec.Item("Feld1") = "Anderer Wert"

            'Bearbeitung beenden
            LastRec.EndEdit()

            'Den letzten Datensatz löschen
            LastRec.Delete()

            '-------------------------------- 

            'Eigenes DataTable Objekt definieren

            With myDataTable

                .Columns.Add("Feld1", GetType(String))
                .Columns.Add("Feld2", GetType(Int32))

            End With

            NewRecord = myDataTable.NewRow()
            With NewRecord

                .Item("Feld1") = "Neuer Wert"
                .Item("Feld2") = "Neuer Wert für Feld 2"
                .Item("Feld3") = 5

            End With
            myDataTable.Rows.Add(NewRecord)

        Catch ex As Exception
            Messagebox.Show("Fehler!")
        End Try

    End Sub

End Class

Listing 4

Daten aktualisieren - DataAdapter II  

Sobald die Daten im DataTable-Objekt geändert wurden, erhält der Datensatz einen Zeilenstatus (RowState). Das ist wichtig für die Aktualisierung der Datenquelle, denn nur so können geänderte Daten erkannt werden. Nachdem die Daten aktualisiert wurden, wird der Zeilenstatus jeder Zeile zurückgesetzt. Wer manuell den Zeilenstatus ändern möchte muss für das Objekt (DataSet, DataTable oder DataRow) die Methode "AcceptChanges" ausführen.

Damit die Daten aktualisiert werden können, müssen dem DataAdapter-Objekt die SQL-Befehle zur Manipulation vorliegen (Insert, Update, Delete). Alternativ kann auch ein CommandBuilder die Befehle generieren. Einzige Bedingung hier: Im betroffenden DataTable-Objekt muss ein Primärschlüssel definiert sein (Eigenschaft PrimaryKey).

Wichtig: Wenn Sie eine Stored Procedure zur Datenauswahl (Select) verwenden, müssen Sie zunächst die Methode "DeriveParameters" ausführen und das Command-Objekt übergeben. Leider funktioniert "DeriveParameters" bei Microsoft Access nicht. Daher wird in diesem Beispiel der SQLClient verwendet.

Imports System
Imports System.Data
Imports System.Data.SqlClient

Public Class Datenbeispiel

    Public Sub Main()
        Try

            'Connectionstring muss festgelegt werden
            Dim sqlCn As New SqlConnection("...")
            Dim sqlDa As New SqlDataAdapter("SELECT * FROM mytable;", sqlCn)
            Dim Data As New DataTable
            Dim newrw As DataRow
            'load data
            sqlDa.Fill(Data)

            'add a new row
            newrw = Data.NewRow
            newrw.Item(0) = 5
            Data.Rows.Add(newrw)

            'get sql commands
            Dim sqlbui As New SqlCommandBuilder(sqlDa)
            With sqlbui
                sqlDa.InsertCommand = sqlbui.GetInsertCommand
                sqlDa.DeleteCommand = sqlbui.GetDeleteCommand
                sqlDa.UpdateCommand = sqlbui.GetUpdateCommand
            End With

            sqlDa.Update(Data)

        Catch ex As Exception
            MessageBox.Show("Fehler!")
        End Try

    End Sub

End Class

Listing 5

Die Kompaktdatenbank - Das DataSet  

Neben den DataAdapters, DataTables und allen weiteren ADO.NET-Objekten hat Microsoft noch ein Objekt, dass alle unter einen Hut bringt, mitgebracht. Das DataSet kann eine komplette Datenbank darstellen, mit Verknüpfungen, Schlüsseln und weiteren Objekten. Jedes DataTable-Objekt hat die Eigenschaft PrimaryKey. Wird die Methode Rows.Find in einem DataTable-Objekt aufgerufen, müssen ein oder mehr Werte für die Suche angegeben werden. Die Suche findet ausschließlich über den Primärschlüssel statt. Möchte man nach anderen Feldern suchen, muss man die Select-Methode verwenden.

Mit Primärschlüsseln können auch Verknüpfen erstellt werden. Verknüpfungen sind sehr nützlich, sie können genauso wie Datenbankverknüpfungen behandelt werden. Es ist möglich sie zu joinen (über GetParentRows, bzw. GetChildRows) und es kann referenzielle Integrität gewährleistet werden.

Imports System
Imports System.Data

Public Class Datenbeispiel

    Public Shared Sub Main()

        Dim DataExample As New DataSet
        'Tabellen wurden bereits geladen und
        'per DataExample.Tables.Add(DataTable)
        'ins DataSet gelegt.

        'Im DataSet liegen 2 Tabellen
        '1. Tabelle: t_Kunden
        'KundenID int (Primärschlüssel)
        'Vorname varchar
        'Nachname varchar
        '2. Tabelle: t_Bestellungen
        'BestellID int (Primärschlüssel)
        'KundenID int
        'Bestelldaten varchar

        DataExample.Relations.Add( _
            New DataRelation("rel_Kunden_Bestellungen", _
                DataExample.Tables("t_Kunden").Columns("KundenID"), _
                DataExample.Tables("t_Bestellungen").Columns("KundenID"), _
                True))

        'Alle Bestellungen mit der Kundennr. 5 abrufen:
        Dim Kunde As DataRow = DataExample.Tables("t_Kunden").Rows.Find(5)
        If Kunde Is Nothing Then
            MessageBox.Show("Kundennr. 5 nicht gefunden!")
            Return
        End If
        Dim Bestellungen() As DataRow = Kunde.GetChildRows("rel_Kunden_Bestellungen")

        'Ausgabe
        For Each Bestellung As DataRow In Bestellungen
            Debug.WriteLine(Bestellung.ItemArray().ToString)
        Next
    End Sub

End Class

Listing 6

Ausblick  

ADO.NET hat natürlich noch viele weitere Möglichkeiten, darunter auch Transaktionen. Dieses Tutorial sollte Ihnen aber helfen den Einstieg in ADO.NET zu finden und Sie auffordern weiter zu erforschen und entdecken. Das Prinzip von ADO.NET sollte Ihnen hier nocheinmal klar gemacht werden: ADO.NET hält keine Verbindung zur Datenbank und es ist theoretisch sogar möglich mit DataSets, DataTables und weiteren Datenobjekten zu arbeiten ohne Datenquelle. Ein DataSet-Objekt hat die Methode "WriteXML" und "WriteXMLSchema" (in .NET 2.0 kann das auch das DataTable-Objekt) und somit können Sie auch Ihre Daten in einer XML-Datei speichern. Dennoch ist XML natürlich nicht die Lösung, wenn es um größere Datenmengen geht und schnelle Abfragen gefragt sind.

ADO.NET wird auch in den Folgeversionen auf dem selben Prinzip aufbauen, sodass gravierende Umstellungen wie von ADO Classic nach ADO.NET auszuschließen sind.

Mit freundlichem Gruß
Christian Dernehl

Ihre Meinung  

Falls Sie Fragen zu diesem Tutorial haben oder Ihre Erfahrung mit anderen Nutzern austauschen möchten, dann teilen Sie uns diese bitte in einem der unten vorhandenen Themen oder über einen neuen Beitrag mit. Hierzu können sie einfach einen Beitrag in einem zum Thema passenden Forum anlegen, welcher automatisch mit dieser Seite verknüpft wird.