ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf ·...

36
1 ADO Im vorherigen Kapitel haben Sie bereits erfahren, dass DAO die bevorzugte Datenzugriffs- Bibliothek ist, wenn es um die Entwicklung reiner Access-Anwendungen geht. ADO (ActiveX Data Objects) war von Microsoft als Nachfolger von DAO geplant. Es eröffnet wesentlich mehr Möglichkeiten, die sich aber vor allem dann bemerkbar machen, wenn Sie ein alternatives Backend wie beispielsweise Microsoft SQL Server oder MySQL verwenden. Der Fokus dieses Buchs richtet sich auf die Entwicklung reiner Access-Datenbankan- wendungen. Daher sollen die Möglichkeiten von Access in Zusammenarbeit mit dem SQL Server hier nicht betrachtet werden. Zusatzkapitel zum Buch Access 2010 - Das Grundlagenbuch für Entwickler www.access-entwicklerbuch.de/2010

Transcript of ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf ·...

Page 1: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1

ADO

Im vorherigen Kapitel haben Sie bereits erfahren, dass DAO die bevorzugte Datenzugriffs-Bibliothek ist, wenn es um die Entwicklung reiner Access-An wen dun gen geht. ADO (ActiveX Data Objects) war von Microsoft als Nach folger von DAO geplant.

Es eröffnet wesentlich mehr Mög lich keiten, die sich aber vor allem dann bemerkbar machen, wenn Sie ein alternatives Backend wie beispielsweise Microsoft SQL Server oder MySQL verwenden.

Der Fokus dieses Buchs richtet sich auf die Entwicklung reiner Access-Daten bank an-wen dungen. Daher sollen die Mög lichkeiten von Access in Zusammenarbeit mit dem SQL Server hier nicht betrachtet werden.

Zusatzkapitel zum Buch

Access 2010 - Das Grundlagenbuch für Entwickler

www.access-entwicklerbuch.de/2010

Page 2: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

978

Zusatzkapitel ADO

Ent wick ler, die jetzt noch reine Access-Anwendungen pro grammieren, aber diese im Hinblick auf einen spä teren Wechsel auf den SQL Server direkt auf dieses Backend vorbereiten möchten, sollen natürlich nicht außen vor bleiben – zumal ADO auch für reine Access-An wendungen einige Features bereithält, die DAO nicht bietet.

BEISPIELDATENBANK

Die Beispieldatei zu diesem Kapitel finden Sie unter dem Namen ADO.accdb auf www.acciu.de/aeb2010.

Wegen des gegenüber DAO wesentlich größeren Funk tions umfangs könnte über ADO ein eigenes Buch geschrie ben werden. Aus Platzgründen wird das Thema hier je-doch ein wenig eingeschränkt – und zwar so, dass Sie die Techniken, die Sie im vor-herigen Kapitel über DAO ken nen gelernt haben, auch mit ADO einsetzen können. Na-türlich soll auch die eine oder andere Spezialität von ADO nicht unerwähnt bleiben. Viele bereits in »DAO« ab Seite 493 enthaltene Informationen gelten auch für den Um gang mit ADO. Dies bezieht sich vor allem auf formale Techniken wie den Umgang mit Auflistungen, die Verwendung von Punkt oder Ausrufezeichen für den Bezug auf Elemente und Eigenschaften oder das De klarieren und Instanzieren von Objekten. Wenn Sie Informationen zu diesen Themen be nötigen, schlagen Sie am besten im oben ge-nann ten Kapitel nach.

ADO-Neuigkeiten

Mit Access 2010 kommt nach Access 2007 wiederum keine neue ADO-Version. Der mit Access 2007 eingeführte JET-OLE DB-Provider namens Microsoft Office 12.0 Access Database Engine OLE DB Provider (Micro soft.ACE.OLEDB.12.0) findet weiterhin Verwendung. Im Gegensatz zu DAO mit den Objekten Recordset2 und Field2 gibt es unter ADO keine Möglichkeit, die in Attachment- oder mehrwertigen Feldern gespeicherten Daten über ein zusätzliches Recordset auszulesen. Daher kann man nur über die »Unterfelder« auf die in den verknüpften, verborgenen Tabellen enthaltenen Daten zugreifen. Wie dies funktioniert, erfahren Sie unter »Daten eines Recordsets mit mehrwertigen Feldern ausgeben« auf Seite 992 und »Daten eines Recordsets mit Attachment-Feldern ausge-ben« auf Seite 993.

1.1 Zugriff auf eine Datenquelle herstellen

Obgleich Sie im Folgenden feststellen werden, dass viele Vorgehensweisen unter DAO und ADO gleich ablaufen, unterscheidet sich das Objektmodell von ADO in einigen Punk-

Page 3: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

979

Zugriff auf eine Datenquelle herstellen

ten vom DAO-Objektmodell. Das macht sich beim Zugriff auf die gewünschte Da ten bank sofort bemerkbar, wie der folgende Abschnitt zeigen wird.

Connection und ConnectionString

Das beginnt damit, dass nicht das Database-Objekt, sondern das Connection-Objekt Ur-sprung aller lesenden, schreibenden und sonstigen Zugriffe auf die Tabellen der Da ten-bank ist. Das Connection-Objekt enthält immer einen ConnectionString, der Informationen über die Verbindung zur gewünschten Datenbank enthält. Diesen ConnectionString stellt man entweder selbst zusammen oder man lässt sich dabei unterstützen. Die einfachste Methode dazu ergibt sich beim Zugriff auf die aktuelle Datenbank. In diesem Fall brau-chen Sie einfach nur auf das Connection-Objekt des bestehenden CurrentProject-Objekts zuzugreifen.

Public Sub Verbindung()

Dim cnn As ADODB.Connection

Set cnn = CurrentProject.Connection

With cnn

Debug.Print cnn.ConnectionString

End With

End Sub

Listing 1.1: Verweisen auf eine Verbindung zur aktuellen Datenbank und Ausgabe der Connection-String-Eigenschaft

Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa so aus – gut, dass Sie diesen Ausdruck nicht selbst zusammenstellen müssen:

Provider=Microsoft.ACE.OLEDB.12.0Microsoft.ACE.OLEDB.12.0;User ID=Admin;Data Source=E:\

ADO.accdbmdb;Mode=Share Deny None;Extended Properties="";Jet OLEDB:System database=C:\

Dokumente und Einstellungen\Administrator\Anwendungsdaten\Microsoft\Access\System.

mdw;Jet OLEDB:Registry Path= Software\Microsoft\Office\12.0\Access\Access Connectivity

EngineSoftware\Microsoft\Office\11.0\Access\Jet\4.0;Jet OLEDB:Database Password="";Jet

OLEDB:Engine Type=65;Jet OLEDB:Database Locking Mode=1;Jet OLEDB:Global Partial Bulk

Ops=2;Jet OLEDB:Global Bulk Transactions=1;Jet OLEDB:New Database Password="";Jet

OLEDB:Create System Database=False;Jet OLEDB:Encrypt Database=False;Jet OLEDB:Don't

Copy Locale on Compact=False;Jet OLEDB:Compact Without Replica Repair=False;Jet

OLEDB:SFP=False;Jet OLEDB:Support Complex Data=True

Was die Parameter im Einzelnen bedeuten, soll hier gar nicht aufgeschlüsselt werden. Für die Verwendung der Datenbank, zu der auch das VBA-Projekt gehört, reicht die Kenntnis, dass CurrentProject.Connection die richtige Verbindung liefert.

Für den Fall, dass Sie einmal eine Verbindung zu einer externen Datenquelle herstellen möchten, brauchen Sie den ConnectionString auch nicht unbedingt manuell zusammen-

Page 4: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

980

Zusatzkapitel ADO

zustellen. Zur Ermittlung der passenden Parameter können Sie auch einen Dialog ver-wenden, der bei der Festlegung der Parameter behilflich ist.

Die folgende Routine erzeugt eine Instanz des DataLinks-Objekts und zeigt mit der Methode PromptNew den Dialog zum Anlegen einer neuen Verbindungszeichenfolge an (siehe Abbildung 1.1).

Public Function ConnectionStringErmitteln()

ConnectionStringErmitteln = CreateObject("DataLinks").PromptNew

End Function

Listing 1.2: Aufruf des Dialogs zum Ermitteln einer Verbindungszeichenfolge

Mit dem gleichen Dialog können Sie nicht nur die Eigenschaften neuer Verbindungen auswählen und zurückgeben lassen, sondern auch die Eigenschaften von CurrentProject.Connection etwas übersichtlicher ausgeben (siehe Abbildung 1.2). Dazu müssen Sie die aufrufende Routine geringfügig abändern:

Public Function ConnectionStringBearbeiten()

ConnectionStringBearbeiten = _

CreateObject("DataLinks").PromptEdit(CurrentProject.Connection)

End Function

Listing 1.3: Aufrufen des Dialogs Datenverknüpfungseigenschaften für eine bestehende Ver-bindungs zeichenfolge

Abbildung 1.1: Anlegen einer neuen Verbindung

Page 5: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

981

Manipulation des Datenmodells

Abbildung 1.2: Bearbeiten von CurrentProject.Connection

1.2 Manipulation des Datenmodells

Die Manipulation von Tabellen, Feldern und anderen Datenbankobjekten erfolgt nicht über ADO selbst, sondern über die Objekte, Methoden und Eigenschaften der Bibliothek ADOX. Die entsprechende Bibliothek im Verweise-Dialog heißt Microsoft ADO Ext. 2.8 for DDL and Security (oder älter).

1.2.1 Anlegen einer Tabelle

Zum Anlegen einer Tabelle mit reinen ADO-Mitteln benötigen Sie das Catalog-Objekt der ADOX-Bibliothek (es ginge ja auch mit CurrentProject.Execute "CREATE TABLE..."). Dieses wird mit der Eigenschaft ActiveConnection auf die aktuelle Datenbank eingestellt. Zum Löschen einer eventuell schon vorhandenen gleichnamigen Tabelle stellt das Catalog-Objekt die Delete-Methode der Tables-Auflistung zur Verfügung.

Anschließend wird ein neues Table-Objekt erstellt und mit dem Namen tblUnternehmen versehen. Bevor die Tabelle an die Tables-Auflistung angehängt und damit verfügbar ge-macht wird, fügen Sie zwei Felder an: UnternehmenID und Unternehmen. Dabei werden zwei unterschiedliche Vorgehensweisen verwendet: Die erste instanziert zunächst ein neues Column-Objekt, füllt dessen Eigenschaften mit den entsprechenden Daten und fügt es dann an die Columns-Auflistung des Table-Objekts an. Die zweite übergibt die benötigten Informationen direkt beim Anfügen eines neuen Feldes an das Table-Objekt.

Nach dem Anlegen werden die Tables-Auflistung und der Navigationsbereich aktuali-siert.

Page 6: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

982

Zusatzkapitel ADO

Public Sub TabelleAnlegen_Unternehmen()

Dim cat As ADOX.Catalog

Dim tbl As ADOX.Table

Dim col As ADOX.Column

Set cat = New ADOX.Catalog

cat.ActiveConnection = CurrentProject.Connection

'Bestehende Tabelle löschen

cat.Tables.Delete "tblUnternehmen"

'Verweis auf neues Table-Objekt

Set tbl = New ADOX.Table

'Name der Tabelle zuweisen

tbl.Name = "tblUnternehmen"

'Feld neu erstellen und per Objektvariable referenzieren

Set col = New ADOX.Column

col.Name = "UnternehmenID"

col.Type = adInteger

tbl.Columns.Append col

'Noch ein Feld erstellen, kurze Fassung

tbl.Columns.Append "Unternehmen", adVarWChar, 30

'Tabelle anhängen und Katalog aktualisieren

With cat.Tables

.Append tbl

.Refresh

End With

'Navigationsbereich aktualisieren

Application.RefreshDatabaseWindow

Set tbl = Nothing

Set cat = Nothing

End Sub

Listing 1.4: Anlegen einer Tabelle mit ADOX

Konstanten für Datentypen unter ADO und ADOX

Tabelle 1.1 zeigt die häufigsten ADOX-Konstanten für die unterschiedlichen Daten typen.

Konstante Datentyp

adBigInt Big Integer

adBinary Binary

adBoolean Boolean

adUnsignedTinyInt Byte

adChar Char

Page 7: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

983

Manipulation des Datenmodells

Konstante Datentyp

adCurrency Currency

adDate Date/Time

adNumeric Decimal

adDouble Double

adGUID GUID

adSmallInt Integer

adInteger Long

adLongVarBinary Long Binary (OLE Object), Attachment.FileData

adLongVarWChar Memo

adNumeric Numeric

adSingle Single

adWChar, adVarWChar Text (Unicode)

adDBTime Time

adIDispatch Attachment, ComplexTypes

adDBTimeStamp Time Stamp

Tabelle 1.1: Konstanten für den Datentyp

1.2.2 Autowert anlegen

Wenn Sie das Feld UnternehmenID als Autowert festlegen möchten, müssen Sie in obi-ger Routine noch einige Zeilen hinter dem Anlegen des Feldes hinzufügen:

'Anlegen eines Autowertes

With tbl.Columns("UnternehmenID")

.ParentCatalog = cat

.Properties("AutoIncrement") = True

End With

Die Eigenschaft AutoIncrement gilt nur für Access-Datenbanken.

1.2.3 Löschen einer Tabelle

Das Löschen einer Tabelle erfolgt über die Delete-Methode der Tables-Auflistung. Die fol-gende Routine löscht die soeben erstellte Tabelle und aktualisiert die Tables-Auflistung sowie den Navigationsbereich.

Public Sub TabelleLoeschen_Unternehmen()

Dim cat As ADOX.Catalog

Set cat = New ADOX.Catalog

Page 8: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

984

Zusatzkapitel ADO

cat.ActiveConnection = CurrentProject.Connection

'Bestehende Tabelle löschen

On Error Resume Next

cat.Tables.Delete "tblUnternehmen"

On Error GoTo 0

'Katalog aktualisieren

cat.Tables.Refresh

'Navigationsbereich aktualisieren

Application.RefreshDatabaseWindow

Set cat = Nothing

End Sub

Listing 1.5: Löschen einer Tabelle mit ADOX

1.2.4 Erstellen eines Indexes

Mit der folgenden Routine fügen Sie der Tabelle tblUnternehmen einen Primärindex auf dem Feld UnternehmenID hinzu.

Public Sub IndexErstellen()

Dim cat As ADOX.Catalog

Dim idx As ADOX.Index

Dim tbl As ADOX.Table

Dim col As ADOX.Column

Dim idxs As ADOX.Indexes

'Catalog instanzieren und auf aktuelle Datenbank einstellen

Set cat = New ADOX.Catalog

cat.ActiveConnection = CurrentProject.Connection

'Tabelle festlegen

Set tbl = cat.Tables("tblUnternehmen")

'Verweis auf Indexes-Auflistung erstellen

Set idxs = tbl.Indexes

'Neues Index-Objekt erstellen

Set idx = New ADOX.Index

With idx

'Index-Objekt mit Eigenschaften ausstatten

.Name = "PrimaryKey"

.PrimaryKey = True

.Unique = True

'Column-Objekt mit zu indizierendem Feld erzeugen

'und zur Auflistung der indizierten Columns hinzufügen

Set col = New ADOX.Column

Page 9: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

985

Manipulation des Datenmodells

col.Name = "UnternehmenID"

.Columns.Append col

End With

'Index an die Auslistung Indexes anfügen

idxs.Append idx

Set col = Nothing

Set idx = Nothing

Set idxs = Nothing

Set tbl = Nothing

Set cat = Nothing

End Sub

Listing 1.6: Anlegen eines Index mit ADOX

1.2.5 Löschen eines Indexes

Zum Entfernen eines Indexes verwenden Sie die folgende Routine. Sie setzt die Delete-Methode der Indexes-Auflistung zum Entfernen des Indexes ein.

Public Sub IndexLoeschen()

Dim cat As ADOX.Catalog

Dim tbl As ADOX.Table

Dim idxs As ADOX.Indexes

Set cat = New ADOX.Catalog

cat.ActiveConnection = CurrentProject.Connection

Set tbl = cat.Tables("tblUnternehmen")

Set idxs = tbl.Indexes

'Index aus der Auflistung löschen

idxs.Delete "PrimaryKey"

Set tbl = Nothing

Set idxs = Nothing

Set cat = Nothing

End Sub

Listing 1.7: Löschen eines Indexes aus der Auflistung der Indizes einer Tabelle

1.2.6 Erstellen einer Beziehung

Um eine Beziehung zwischen zwei Tabellen herzustellen, verwenden Sie die folgende Routine.

Voraussetzung ist, dass das Fremdschlüsselfeld der Detailtabelle den gleichen Daten-typ wie das Primärschlüsselfeld der Mastertabelle hat. Außerdem muss der Primär-

Page 10: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

986

Zusatzkapitel ADO

schlüssel der Mastertabelle eindeutig sein. Sind die Voraussetzungen erfüllt (und die angegebenen Tabellen beziehungsweise Felder vorhanden), legt die Routine die Beziehung aus Abbildung 1.3 an.

Wenn Sie zusätzlich Löschweitergabe oder Aktualisierungsweitergaben definieren möchten, müssen Sie die Eigenschaften DeleteRule und UpdateRule des key-Objekts mit den entsprechenden Werten bestücken. Mit der Konstanten adRICascade sorgen Sie für die Weitergabe der jeweiligen Aktion:

Public Sub BeziehungErstellen()

Dim cat As ADOX.Catalog

Dim tbl As ADOX.Table

Dim key As ADOX.key

Set cat = New ADOX.Catalog

cat.ActiveConnection = CurrentProject.Connection

'Tabelle mit dem Fremdschlüsselfeld festlegen

Set tbl = cat.Tables("tblMitarbeiter")

'Neuen Key instanzieren und Eigenschaften zuweisen

Set key = New ADOX.key

key.Name = "ForeignKey"

key.Type = adKeyForeign

'Tabelle mit Primärschlüssel festlegen

key.RelatedTable = "tblUnternehmen"

'Verknüpfungsfeld der Detailtabelle angeben

key.Columns.Append "UnternehmenID"

'Optional: Lösch- oder Aktualisierungsweitergabe

key.DeleteRule = adRICascade

key.UpdateRule = adRICascade

'Verknüpfungsfeld der Mastertabelle angeben

key.Columns("UnternehmenID").RelatedColumn = "UnternehmenID"

'Key an die Keys-Auflistung anhängen

tbl.keys.Append key

Set key = Nothing

Set tbl = Nothing

Set cat = Nothing

End Sub

Listing 1.8: Anlegen einer Beziehung zwischen zwei Tabellen

Page 11: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

987

Zugriff auf Tabellen, Abfragen und die darin enthaltenen Daten

Abbildung 1.3: Mit ADOX erstellte Beziehung

1.2.7 Löschen einer Beziehung

Die Beziehung beziehungsweise den Fremdschlüssel löschen Sie mit der folgenden Routine:

Public Sub BeziehungLoeschen()

Dim cat As ADOX.Catalog

Set cat = New ADOX.Catalog

cat.ActiveConnection = CurrentProject.Connection

'Beziehung in Form des Fremdschlüssels löschen

cat.Tables("tblMitarbeiter").keys.Delete "ForeignKey"

Set cat = Nothing

End Sub

Listing 1.9: Löschen einer Beziehung

1.3 Zugriff auf Tabellen, Abfragen und die darin enthaltenen Daten

In den folgenden Abschnitten erfahren Sie, wie Sie auf die Daten der Datenbank zugrei-fen können.

1.3.1 Ausgeben aller Tabellen

Im vorigen Kapitel zum Thema DAO haben Sie erfahren, wie Sie mit DAO alle Tabellen ausgeben oder prüfen, ob eine Tabelle vorhanden ist. Unter ADO erledigen Sie dies wie in folgendem Beispiel:

Sub DBInfoADO()

Dim rs As New ADODB.Recordset

Dim fld As ADODB.Field

Set rs = CurrentProject.Connection.OpenSchema(adSchemaTables)

Do While Not rs.EOF

Page 12: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

988

Zusatzkapitel ADO

For Each fld In rs.Fields

Debug.Print , fld.Name, "=", fld.Value

Next fld

rs.MoveNext

Debug.Print

Loop

rs.Close

End Sub

Das liefert beispielsweise solche Informationen:

TABLE_CATALOG = Null

TABLE_SCHEMA = Null

TABLE_NAME = tblDateien

TABLE_TYPE = TABLE

TABLE_GUID = Null

DESCRIPTION = Null

TABLE_PROPID = Null

DATE_CREATED = 21.01.2007 14:52:08

DATE_MODIFIED = 21.01.2007 14:52:11

Wenn Sie nur die benutzerdefinierten Tabellen ausgeben möchten, erledigen Sie das etwa so:

Sub DBInfoADO()

Dim rst As New ADODB.Recordset

Dim fld As ADODB.Field

Set rst = CurrentProject.Connection.OpenSchema(adSchemaTables)

Debug.Print "Tabellen:"

Do While Not rst.EOF

For Each fld In rst.Fields

If fld.Name = "TABLE_NAME" And rst("TABLE_TYPE") = "TABLE" Then

Debug.Print fld.Value

End If

Next fld

rst.MoveNext

Loop

rst.Close

End Sub

Es gibt noch einige weitere Konstanten, die Sie der OpenSchema-Methode übergeben können, zum Beispiel die Folgenden – experimentieren Sie einfach mal damit:

» adSchemaColumns

Page 13: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

989

Zugriff auf Tabellen, Abfragen und die darin enthaltenen Daten

» adSchemaConstraintColumnUsage

» adSchemaForeignKeys

» adSchemaIndexes

» adSchemaKeyColumnUsage

» adSchemaPrimaryKeys

» adSchemaProcedures und adSchemaViews (Abfragen)

» adSchemaProviderTypes

» adSchemaReferentialConstraints

» adSchemaStatistics (Beziehungen)

» adSchemaTableConstraints

» adSchemaTrustees (DB-Benutzer)

1.3.2 Prüfen, ob eine Tabelle vorhanden ist

Auch hier brauchen Sie nicht mit ADO zu arbeiten, sondern können die AllTables-Auflistung verwenden:

Public Function IstTabelleVorhanden_ADO(strTabellenname As String) _

As Boolean

Dim objTable As AccessObject

On Error Resume Next

Set objTable = CurrentData.AllTables (strTabellenname)

IstTabelleVorhanden_ADO = Not objTable Is Nothing

End Function

Listing 1.10: Prüfen des Vorhandenseins einer Tabelle

1.3.3 Datensatzgruppe auf Basis einer Tabelle öffnen

Das Öffnen einer Datensatzgruppe erfolgt anders als unter DAO. Die Methode zum Öffnen ist keine Methode des übergeordneten Objekts (bei DAO das Database-Objekt), sondern eine Methode des ADO-Recordset-Objekts selbst. Die Open-Methode erwar-tet den Namen der zu öffnenden Tabelle oder Abfrage beziehungsweise einen SQL-Ausdruck, den Connection-String sowie zwei Parameter zur Angabe des Cursor-Typs und des Sperrmechanismus. Die Beschreibung der verschiedenen Möglichkeiten fin-den Sie im Anschluss an die Routine zum Öffnen einer Datensatzgruppe. Hier tritt offen zu Tage, weshalb es sich lohnt, bei der Variablendeklaration explizit die Bibliothek mit

Page 14: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

990

Zusatzkapitel ADO

anzugeben, aus der die Objekte stammen: Wenn Sie das versäumt haben und die DAO-Bibliothek ist in der Liste der Verweise oberhalb der ADO-Bibliothek angeordnet, sucht die folgende Routine vergeblich die Open-Methode des Recordset-Objekts.

Public Sub DatensatzgruppeOeffnen()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

rst.Open "tblUnternehmen", cnn, adOpenDynamic, adLockOptimistic

With rst

'etwas mit der Datenatzgruppe machen

End With

rst.Close

Set rst = Nothing

Set cnn = Nothing

End Sub

Listing 1.11: Öffnen einer Datensatzgruppe mit ADO

Das eigentliche Öffnen der Datensatzgruppe kann auch so erfolgen, wobei zunächst die Eigenschaften festgelegt werden und erst dann die Da ten satz grup pe geöffnet wird:

rst.ActiveConnection = cnn

rst.LockType = adLockOptimistic

rst.CursorType = adOpenKeyset

rst.Open "tblUnternehmen"

1.3.4 Cursor-Typen

Beim Öffnen einer Datensatzgruppe unter ADO können Sie folgende Cursor-Typen für die Eigenschaft CursorType verwenden:

» adOpenDynamic: Liefert eine Gruppe von Datensätzen und zeigt Daten satz än de run-gen an derer Benutzer an (entspricht dbOpenDynaset unter DAO).

» adOpenForwardOnly: Liefert einen Snapshot der gewünschten Datensätze zum Zeit-punkt des Öffnens des Recordset-Objekts, kann nur vorwärts durchlaufen werden (ent spricht dbOpenForwardOnly unter DAO).

» adOpenKeyset: Liefert Verweise auf die Datensätze der zugrunde liegenden Tabellen (ent spricht keiner DAO-Konstante genau, ist aber fast äquivalent zu dbOpenDynaset und etwas schneller als adOpenDynamic).

Page 15: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

991

Zugriff auf Tabellen, Abfragen und die darin enthaltenen Daten

» adOpenStatic: Liefert einen Snapshot der gewünschten Datensätze zum Zeitpunkt des Öffnens des Recordset-Objekts (entspricht dbOpenSnapshot unter DAO).

Achtung: Bei Recordsets, die mit Connections geöffnet werden, die nicht CurrentProject entsprechen, müssen Sie zusätzlich die CursorLocation auf den Wert adUseClient fest-legen:

cnn.CursorLocation = adUseClient

1.3.5 Sperrung von Daten

Mit dem Parameter LockType legen Sie fest, wie die Daten beim Schreiben gesperrt werden sollen:

» adLockReadonly: Öffnet ein schreibgeschütztes Recordset.

» adLockPessimistic: Sperrt die komplette Speicherseite, in der sich der von einer Än-de rung betroffene Datensatz befindet, sobald die Bearbeitung beginnt.

» adLockOptimistic: Sperrt die komplette Speicherseite, in der sich der von einer Än de-rung betroffene Datensatz befindet, erst, wenn der Datensatz aktualisiert wird.

» adLockBatchOptimistic: Wie adLockOptimistic, aber für die UpdateBatch-Methode.

1.3.6 Datensätze eines Recordsets durchlaufen

Zum Durchlaufen der Datensätze eines Recordsets verwenden Sie beispielsweise die Do While-Schleife, in der Sie nach dem Durchführen der gewünschten Aktion jeweils mit der MoveNext-Methode einen Datensatz weiter springen. Als Abbruchbedingung dient die EOF-Eigenschaft der Datensatzgruppe, die den Wert True erhält, wenn der Datensatzzeiger über den letzten Datensatz hinaus verschoben wurde.

Public Sub DatensaetzeDurchlaufen()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

rst.Open "tblUnternehmen", cnn, adOpenKeyset, adLockOptimistic

Do While Not rst.EOF

With rst

'etwas mit dem aktuellen Datensatz tun

End With

rst.MoveNext

Loop

rst.Close

Page 16: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

992

Zusatzkapitel ADO

Set rst = Nothing

Set cnn = Nothing

End Sub

Listing 1.12: Datensatzgruppe durchlaufen

Das Pendant zur EOF-Eigenschaft ist die BOF-Eigenschaft. Sie erhält den Wert True, wenn der Datensatzzeiger sich vor dem ersten Datensatz der Datensatzgruppe befin-det. Neben der MoveNext-Methode gibt es noch die Methoden MoveFirst, MoveLast und MovePrevious zum Bewegen innerhalb der Datensatzgruppe.

1.3.7 Daten eines Recordsets mit mehrwertigen Feldern ausgeben

ADO bietet keine besondere Möglichkeit, um auf die Inhalte mehrwertiger Felder zuzu-greifen – es gibt also kein Recordset2- oder Field2-Objekt wie unter DAO. Daher können Sie nur auf die in solchen Feldern enthaltenen Daten zugreifen, wenn Sie diese in der Datenherkunft über die »Unterfelder« referenzieren, wie das folgende Beispiel zeigt:

Public Sub DatensaetzeDurchlaufen_MehrwertigesFeld()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

rst.Open "SELECT MehrwertigesFeld.Value " _

& "FROM tblMehrwertigesFeld", _

cnn, adOpenKeyset, adLockOptimistic

Do While Not rst.EOF

With rst

Debug.Print rst.Fields("MehrwertigesFeld.Value")

End With

rst.MoveNext

Loop

rst.Close

Set rst = Nothing

Set cnn = Nothing

End Sub

Listing 1.13: Zugriff auf mehrwertige Felder mit einem ADO-Recordset

Page 17: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

993

Zugriff auf Tabellen, Abfragen und die darin enthaltenen Daten

1.3.8 Daten eines Recordsets mit Attachment-Feldern ausgeben

Der Umgang mit den in Attachment-Feldern gespeicherten Daten sieht prinzipiell wie bei den mehrwertigen Feldern aus:

Public Sub DatensaetzeDurchlaufen_Attachment()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

rst.Open "SELECT DateiID, Datei.FileType, " _

& "Datei.Filename FROM tblDateien", _

cnn, adOpenKeyset, adLockOptimistic

Do While Not rst.EOF

With rst

Debug.Print rst!DateiID, rst.Fields("Datei.FileType"), _

rst.Fields("Datei.Filename")

End With

rst.MoveNext

Loop

rst.Close

Set rst = Nothing

Set cnn = Nothing

End Sub

Listing 1.14: Zugriff auf Attachment-Felder

1.3.9 Anzahl der Datensätze in einer Datensatzgruppe ermitteln

Um die Anzahl der Datensätze zu ermitteln, dürfen Sie nicht die Konstante adOpenFor­ward Only für die Eigenschaft CursorType einsetzen. Außerdem müssen Sie für die Ei gen-schaft CursorLocation den Parameter adUseClient verwenden, da serverseitige Da ten -satz-Cur sor unter ACE das Zählen von Datensätzen nicht unterstützen.

Public Sub Datensatzanzahl()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

rst.CursorLocation = adUseClient

Page 18: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

994

Zusatzkapitel ADO

rst.CursorType = adOpenForwardOnly

rst.LockType = adLockOptimistic

rst.ActiveConnection = cnn

rst.Open "tblUnternehmen"

Debug.Print rst.RecordCount

End Sub

Listing 1.15: Ermitteln der Datensatzanzahl eines Recordsets

1.3.10 Prüfen, ob eine Datensatzgruppe leer ist

Eine einfache Möglichkeit, um herauszufinden, ob eine Datensatzgruppe leer ist, be-steht im Prüfen der EOF­ und der BOF-Eigenschaften der Datensatzgruppe:

Public Sub LeereDatensatzgruppe()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

rst.Open "tblMitarbeiter", cnn, adOpenForwardOnly, adLockOptimistic

If rst.BOF And rst.EOF Then

MsgBox "Die Datensatzgruppe ist leer."

End If

rst.Close

Set rst = Nothing

Set cnn = Nothing

End Sub

Listing 1.16: Prüfen, ob eine Datensatzgruppe leer ist

1.3.11 Ausgabe des Inhalts eines Recordsets

Manchmal möchte man den Inhalt eines Recordsets auf die Schnelle betrachten oder etwa in einer Textdatei speichern. Dabei leistet die GetString-Methode gute Dienste.

Diese Methode ist sehr flexibel und kann, mit zusätzlichen Parametern ausgestattet, die Spalten auch als formatierten Text zurückgeben.

Informationen zu den (optionalen) Parametern finden Sie unter http://msdn.microsoft.com/en-us/library/ms676975%28v=vs.85%29.aspx.

Public Sub DatensatzgruppeAusgeben()

rst.Open "tblUnternehmen", cnn, adOpenForwardOnly, adLockOptimistic

Page 19: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

995

Zugriff auf Tabellen, Abfragen und die darin enthaltenen Daten

Debug.Print rst.GetString

End Sub

Listing 1.17: Ausgeben der Daten einer Datensatzgruppe

1.3.12 Speichern der Daten in einem Array

Wenn Sie die Daten einer Datensatzgruppe in einem Array weiter verarbeiten möch-ten, können Sie mit der GetRows-Methode ein zweidimensionales Array mit den in der Datensatzgruppe enthaltenen Daten füllen.

Die GetRows-Methode hat drei Parameter: Rows gibt an, wie viele Datensätze eingele-sen werden sollen, Start enthält ein Bookmark auf den ersten einzulesenden Datensatz und Fields die Position oder den Namen des einzulesenden Feldes beziehungsweise ein Array mit den Namen der einzulesenden Felder. Ohne die Angabe von Parametern liest GetRows alle Datensätze mit allen Feldern ein.

Public Sub DatensatzgruppeInArray()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Dim varRecordset() As Variant

Dim i As Integer

Dim j As Integer

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

rst.Open "tblUnternehmen", cnn, adOpenForwardOnly, adLockOptimistic

varRecordset = rst.GetRows()

For i = 0 To UBound(varRecordset, 2)

For j = 0 To UBound(varRecordset, 1)

Debug.Print varRecordset(j, i)

Next j

Next i

rst.Close

Set rst = Nothing

Set cnn = Nothing

End Sub

Listing 1.18: Einlesen der Daten einer Datensatzgruppe in ein Array

Page 20: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

996

Zusatzkapitel ADO

1.3.13 Abfragen mit Parametern verwenden

Während Sie unter DAO das QueryDef-Objekt und die Parameters-Auflistung verwendet haben, um Abfragen mit Parametern zu handhaben, stellt ADO für diesen Zweck das Command-Objekt zur Verfügung.

Das folgende Beispiel zeigt, wie Sie ein Recordset auf Basis einer mit Parametern verse-henen Abfrage öffnen. Sie verwenden hier nicht wie bei DAO eine Parameters-Auflistung, sondern geben den Wert eines einzelnen Parameters als String und mehrere Werte in der richtigen Reihenfolge als String-Array an – bei anderen Datentypen für die Parameter verwenden Sie dann eher ein Variant-Array.

Public Sub Parameterabfrage()

Dim cnn As ADODB.Connection

Dim cmd As ADODB.Command

Dim rst As ADODB.Recordset

Dim lngRecordsAffected As Long

Set cnn = CurrentProject.Connection

'Command-Objekt instanzieren

Set cmd = New ADODB.Command

'Aktuelle Verbindung zuweisen

cmd.ActiveConnection = cnn

'auszuführende Abfrage angeben

cmd.CommandText = "qryMitarbeiter"

'Typ des Commands festlegen

cmd.CommandType = adCmdTable

'Command-Objekt ausführen. Der erste Parameter wird nur für

'Aktionsabfragen benötigt, der zweite enthält die Werte für die

'Abfrageparameter. Ein Parameter wird als String, mehrere als

'Array übergeben.

Set rst = cmd.Execute(, "Minhorst")

Do While Not rst.EOF

Debug.Print rst!Vorname, rst!Nachname

rst.MoveNext

Loop

Set rst = Nothing

Set cnn = Nothing

End Sub

Listing 1.19: Erzeugen eines Recordsets auf Basis einer Parameterabfrage

Page 21: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

997

Datensätze suchen

1.4 Datensätze suchen

Zur Suche von Datensätzen gibt es mehrere Möglichkeiten. Wie unter DAO können Sie indizierte Felder mit der Seek-Methode durchsuchen, anderenfalls hilft die Find-Me-thode weiter.

Diese ist allerdings nicht so flexibel wie die Find…-Methoden von DAO, wie Sie nachfol-gend lesen können. Am einfachsten ist es jedoch, die gesuchten Da ten sätze direkt in der Datenherkunft des Recordset-Objekts einzugrenzen.

1.4.1 Gesuchte Datensätze per Source-Eigenschaft des Recordsets ermitteln

Die Source-Eigenschaft eines Recordset-Objekts enthält die dem Recordset-Objekt zu-grunde liegende Tabelle oder Abfrage. Sie können hier auf drei Arten bereits mit dem Öffnen des Recordset-Objekts die gewünschten Daten ausfindig machen:

» Direkte Angabe einer SELECT-Anweisung (jeweils in einer Zeile):

rst.Open "SELECT * FROM Artikel WHERE Artikelname LIKE 'A%'", cnn, adOpenKeyset, adLockOptimistic

» Angabe einer gespeicherten Abfrage:

rst.Open "qryArtikelMitPreisGroesser50", cnn, adOpenKeyset, adLockOptimistic

» Kombination aus SELECT-Anweisung und gespeicherter Abfrage:

rst.Open "SELECT * FROM qryArtikelMitPreisGroesser50 WHERE Artikelname LIKE 'T%'", cnn, adOpenKeyset, adLockOptimisticJoker in Zeichenketten unter ADO und SQL

Wenn Sie wie in den obigen Beispielen Vergleichsausdrücke mit Platzhaltern verwen-den möchten, müssen Sie die SQL Server-Syntax verwenden. Dabei entspricht der Platzhalter für beliebig viele Zeichen dem Prozentzeichen (%) und nicht wie in VBA oder Abfragen, die Sie über die Abfrageentwurfsansicht erstellen (siehe Abbildung 1.4), dem Sternchen (*). Der Platzhalter für ein einzelnes Zeichen entspricht dem Unterstrich (_) und nicht wie in VBA oder Abfragen dem Fragezeichen (?).

Page 22: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

998

Zusatzkapitel ADO

Abbildung 1.4: Joker für beliebig viele Zeichen in Abfragen

1.4.2 Seek

Wenn Sie mit der Seek-Methode nach Daten suchen möchten, müssen zwei Bedingungen erfüllt sein: Das zu durchsuchende Feld muss indiziert sein und Sie müssen die Konstante adCmdTableDirect als Option beim Öffnen der Datensatzgruppe festlegen. Ersteres prüfen Sie ganz einfach, indem Sie in der Entwurfsansicht einer Tabelle den Indizes-Dialog einblenden (Ribbon-Eintrag Entwurf|Einblenden/Ausblenden|Indizes, sie-he Abbildung 1.5). Letzteres impliziert, dass Sie nur auf einzelne Tabellen, aber nicht auf Abfragen oder verknüpfte Tabellen zugreifen können.

Abbildung 1.5: Anzeigen der Indizes einer Tabelle

Page 23: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

999

Datensätze suchen

Die Option adcmdTableDirect verwenden Sie mit der Open-Methode des Recordset-Objekts. Die folgende Routine zeigt, wie Sie mit der Seek-Methode einen bestimmten Datensatz einer Tabelle finden und den Wert seines Primärschlüsselfeldes ausgeben.

Im Gegensatz zur weiter unten vorgestellten Find-Methode enthält das Recordset-Objekt nicht alle Datensätze, die dem Suchkriterium entsprechen, sondern es wird lediglich der Datensatzzeiger auf einem Datensatz platziert, der den mit der Seek-Methode über-gebenen Parametern entspricht.

Dabei gibt es verschiedene Varianten, die Sie mit dem Parameter SeekOption übergeben. Die wichtigsten sind folgende:

» adSeekFirstEQ: Setzt den Datensatzzeiger auf den ersten Datensatz mit dem angege-benen Wert.

» adSeekLastEQ: Setzt den Datensatzzeiger auf den letzten Datensatz mit dem ange-gebenen Wert.

Seek ist unter den gegebenen Bedingungen die schnellste Möglichkeit, um auf einen bestimmten Datensatz zuzugreifen.

Public Sub SuchenMitSeek()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

'Recordset mit direktem Zugriff auf die Tabelle öffnen

rst.Open "Artikel", cnn, adOpenKeyset, adLockOptimistic, _

adCmdTableDirect

'Index festlegen: Achtung, Indexname und nicht den Feldnamen verwenden!

rst.Index = "Artikelname"

'Suche starten

rst.Seek "Chocolade", adSeekFirstEQ

'Aktuellen Datensatz anzeigen

If Not rst.EOF Then

Debug.Print rst![Artikel-Nr]

End If

rst.Close

Set rst = Nothing

Set cnn = Nothing

End Sub

Listing 1.20: Suche mit der Seek-Methode

Page 24: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1000

Zusatzkapitel ADO

1.4.3 Find

Die Find-Methode ist weniger flexibel als die Find…-Methoden von DAO. Sie fasst zwar die Funktion der Find…-Methoden von DAO zusammen, beschränkt allerdings beispiels-weise die möglichen Kriterien auf ein einziges.

Die Find-Methode bietet vier Parameter, von denen nur die Angabe des Suchkriteriums Pflicht ist. Als Suchkriterium dient ein aus Feldname, Vergleichsoperator und Ver-gleichs wert zusammengesetzter Ausdruck, wobei die gleichen Regeln wie für die WHERE-Klau sel von SQL-Abfragen gelten (siehe auch »Access-SQL« ab Seite 453). Die übrigen Pa rameter:

» SkipRecords legt fest, wie viele Datensätze von der aktuellen Position aus übersprun-gen werden sollen, und ist beispielsweise wichtig, wenn Sie bereits einen Datensatz ge funden haben und bei der Suche des nächsten Datensatzes nicht auf dem aktuel-len Datensatz stehen bleiben möchten.

» SearchDirection erwartet eine der Konstanten adSearchForward oder adSearchBack­ward und sucht in der entsprechenden Richtung.

» Start erwartet die Position des Datensatzzeigers für einen vom ersten Datensatz ab-weichenden Startpunkt.

Wenn die Find-Methode einen Datensatz findet, positioniert sie den Datensatzzeiger auf dem gefundenen Datensatz. Sollen weitere Datensätze gefunden werden, wie etwa im folgenden Beispiel, verwenden Sie innerhalb einer Do While-Schleife erneut die Find-Me thode – mit dem gleichen Kriterium, aber dem Wert 1 für den Parameter SkipRecords. Dies hat den Grund, dass die Find-Methode mit der Suche immer in dem Datensatz be-ginnt, auf dem sich aktuell der Datensatzzeiger befindet.

Eine solche Suche bedingt immer die Prüfung auf die Eigenschaft EOF oder BOF der Da tensatzgruppe (je nach Suchrichtung), da dies die Position des Datensatzzeigers ist, wenn kein Datensatz gefunden wurde. Das entspricht dann der Eigenschaft Recordset.No Match unter DAO.

Public Sub SuchenMitFind()

Dim cnn As ADODB.Connection

Dim rst As ADODB.Recordset

Dim strKriterium As String

Set cnn = CurrentProject.Connection

Set rst = New ADODB.Recordset

rst.Open "Artikel", cnn, adOpenKeyset, adLockOptimistic

strKriterium = "[Artikelname] LIKE 'A*'"

rst.Find strKriterium

Do While Not rst.EOF

Page 25: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1001

Datensätze suchen

Debug.Print rst!Artikelname

rst.Find strKriterium, 1

Loop

End Sub

Listing 1.21: Suche nach allen Datensätzen, deren Artikelname mit A beginnt

1.4.4 Filtern

Genau wie DAO enthält das Recordset-Objekt auch unter ADO eine Eigenschaft namens Filter. Unter DAO weist man einem Recordset-Objekt den Filter zu und erhält das ge-filterte Ergebnis, wenn man ein weiteres Recordset-Objekt auf Basis des ersten öffnet. Dies ist unter ADO einfacher: Hier weisen Sie einfach das gewünschte Filterkriterium zu und können direkt im gleichen Recordset auf das gefilterte Ergebnis zugreifen.

Public Sub FilternEinesRecordset()

rst.Open "Artikel", cnn, adOpenKeyset, adLockOptimistic

rst.Filter = "Artikelname LIKE 'A*'"

Do While Not rst.EOF

Debug.Print rst!Artikelname

rst.MoveNext

Loop

End Sub

Listing 1.22: Filtern aller Datensätze, deren Artikelname mit A beginnt

Um den Filter zu entfernen, verwenden Sie die Konstante adFilterNone an Stelle eines Parameters:

rst.Filter = adFilterNone

Filter unterliegen unter ADO einigen Einschränkungen. Mehr dazu unter folgendem Link: http://msdn.microsoft.com/en-us/library/ms676691%28v=VS.85%29.aspx

1.4.5 Sortieren

Die Datensätze eines Recordsets können Sie entweder bereits über die Datenherkunft oder durch nachträgliches Hinzufügen eines Sortierkriteriums sortieren. In der Da ten-her kunft gibt es zwei Möglichkeiten:

» Sie öffnen die Datensatzgruppe mit der Option adTableDirect. In diesem Fall kommt die im Dialog Indizes angegebene Sortierung zur Anwendung.

Page 26: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1002

Zusatzkapitel ADO

» Sie öffnen eine gespeicherte Abfrage mit voreingestellter Sortierreihenfolge oder geben einen SQL-Ausdruck mit einem entsprechenden Sortierkriterium an.

Sortieren nach dem Öffnen des Recordsets

Wie in DAO bietet auch ADO eine Eigenschaft zum Angeben eines Sortierkriteriums. Voraussetzung für seinen Einsatz ist, dass das Recordset-Objekt einen clientseitigen Cur sor verwendet. Wie auch die Filter-Eigenschaft wirkt sich die Sort-Eigenschaft un-mittelbar auf die aktuelle Datensatzgruppe aus.

Nach dem Öffnen des Recordsets können Sie eine Sortierung mit der Sort-Eigenschaft vornehmen:

Public Sub SortierenEinesRecordset()

rst.CursorLocation = adUseClient

rst.Open "Artikel", cnn, adOpenDynamic, adLockOptimistic

rst.Sort = "Artikelname ASC"

Do While Not rst.EOF

Debug.Print rst!Artikelname

rst.MoveNext

Loop

End Sub

Listing 1.23: Nachträgliches Sortieren einer Datensatzgruppe

1.4.6 Lesezeichen

Auch ADO-Recordsets bieten eine Bookmark-Eigenschaft. Bookmarks dienen dazu, sich die Position eines Datensatzes zu merken und auf einen gemerkten Datensatz zurück-zuspringen. Daher ist diese Eigenschaft les- und schreibbar. Unter Verwendung eines Bookmarks können Sie beispielsweise von einem bestimmten Datensatz an das Ende der Datensatzgruppe und anschließend wieder zurück zum ursprünglichen Datensatz springen.

Public Sub SpringenMitBookmark()

Dim varLesezeichen As Variant

rst.Open "Artikel", cnn, adOpenKeyset, adLockOptimistic

rst.Find "Artikelname = 'Chai'"

Debug.Print rst!Artikelname

Page 27: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1003

Datensätze bearbeiten

varLesezeichen = rst.Bookmark

rst.MoveLast

Debug.Print rst!Artikelname

rst.Bookmark = varLesezeichen

Debug.Print rst!Artikelname

End Sub

Listing 1.24: Hin- und herspringen mit Bookmarks

1.5 Datensätze bearbeiten

Daten lassen sich mit ADO auf verschiedene Art manipulieren. Nachfolgend erfahren Sie, wie Sie Daten mit Aktionsabfragen und mit den Methoden des Recordset-Objekts bearbeiten.

1.5.1 Datensatz anlegen

Zum Anlegen eines neuen Datensatzes verwenden Sie AddNew- und die Update-Methode. Dazwischen stellen Sie die Felder der Datensatzgruppe auf die gewünschten Werte ein.

Public Sub DatensatzAnlegen()

rst.Open "tblUnternehmen", cnn, adOpenKeyset, adLockOptimistic

rst.AddNew

rst!Unternehmen = "Pearson Education Deutschland GmbH"

rst.Update

End Sub

Listing 1.25: Neuen Datensatz anlegen

Sie brauchen im Unterschied zu DAO die Update-Methode nicht auszuführen, wenn Sie den Datensatz wechseln, bevor Sie das Recordset-Objekt schließen. Wenn Sie nach dem An legen beispielsweise sofort noch einen weiteren Datensatz anlegen möchten, brau-chen Sie die Update-Anweisung nur nach dem Anlegen des zweiten Datensatzes und vor dem Schließen der Datensatzgruppe aufzurufen:

rst.AddNew

rst!Unternehmen = "Pearson Education Deutschland GmbH"

rst.AddNew

Page 28: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1004

Zusatzkapitel ADO

rst!Unternehmen = "amisoft"

rst.Update

Wenn Sie mit AddNew das Anlegen eines neuen Datensatzes starten und das Recordset-Ob jekt schließen, bevor Sie die Update-Methode ausgeführt haben, lösen Sie einen Lauf-zeit fehler aus:

rst.AddNew

rst!Unternehmen = "Pearson Education Deutschland GmbH"

'Schließen ohne Update löst Laufzeitfehler aus

rst.Close

1.5.2 Datensatz bearbeiten

Während Sie unter DAO vor dem Bearbeiten eines Datensatzes die Edit-Methode aufru-fen mussten, können Sie unter ADO Änderungen am aktuellen Datensatz direkt vorneh-men. Die Änderungen übernehmen Sie schließlich mit Update.

Public Sub DatensatzAendern()

rst.Open "tblUnternehmen", cnn, adOpenKeyset, adLockOptimistic

rst.Find "Unternehmen = 'Pearson Education Deutschland GmbH'"

rst!Unternehmen = "Addison Wesley"

rst.Update

End Sub

Listing 1.26: Datensatz ändern

1.5.3 Datensatz löschen

Zum Löschen eines Datensatzes verschieben Sie den Datensatzzeiger auf den zu lö-schenden Datensatz und entfernen diesen mit der Delete-Methode.

Public Sub DatensatzLoeschen()

rst.Open "tblUnternehmen", cnn, adOpenKeyset, adLockOptimistic

rst.Find "Unternehmen = 'Pearson Education Deutschland GmbH'"

rst.Delete

End Sub

Listing 1.27: Löschen eines Datensatzes

Page 29: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1005

Transaktionen

1.5.4 Aktionsabfragen ausführen

Aktionsabfragen führen Sie unter ADO mit der Execute-Methode des Connection-Objekts aus. Diese Methode erwartet als ersten Parameter den auszuführenden SQL-Ausdruck. Als zweiten Parameter können Sie eine Variable angeben, in der die Anzahl der durch die Aktionsabfrage betroffenen Datensätze gespeichert wird. Diese können Sie nachher weiter verwenden.

Public Sub AktionsabfrageAusfuehren()

Dim cnn As ADODB.Connection

Dim cmd As ADODB.Command

Dim lngRecordsAffected

Set cnn = CurrentProject.Connection

cnn.Execute "INSERT INTO tblUnternehmen(Unternehmen) " _

& "VALUES('Addison-Wesley')", lngRecordsAffected

Debug.Print lngRecordsAffected

Set cnn = Nothing

End Sub

Listing 1.28: Ausführen einer Aktionsabfrage

1.6 Transaktionen

Transaktionen funktionieren unter ADO prinzipiell wie unter DAO. Der wichtigste Unterschied ist, dass die Bezeichnungen der drei Methoden zum Durchführen von Transaktionen vereinheitlicht wurden. Diese heißen jetzt:

» BeginTrans

» CommitTrans

» RollbackTrans

Außerdem gehören die Methoden zum Connection-Objekt – unter DAO war es das Work­space-Objekt. Weitere Informationen zu Transaktionen finden Sie in »Transaktionen« auf Seite 553.

1.7 Besonderheiten von ADO gegenüber DAO

ADO bietet einige Besonderheiten gegenüber DAO. So ist es möglich, eine Da ten satz-grup pe zu speichern, Recordset-Objekte ohne Datenherkunft in Form einer Tabelle oder

Page 30: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1006

Zusatzkapitel ADO

Ab frage zu verwenden oder Recordsets von der Datenherkunft zu trennen und anschlie-ßend wieder zu verbinden.

1.7.1 Datensatzgruppe speichern

Sie können eine Datensatzgruppe in einem Microsoft-eigenen Format oder im XML-For mat speichern, solange diese keine Anlagen oder mehrwertigen Felder enthält. Die folgende Routine speichert den Inhalt der Tabelle Personal in der Da tei Personal.xml im Verzeichnis der Datenbank.

Public Sub DatensatzgruppeSpeichern()

rst.Open "Personal", cnn, adOpenStatic, adLockOptimistic

rst.Save CurrentProject.Path & "\Personal.xml", adPersistXML

End Sub

Listing 1.29: Speichern einer Datensatzgruppe

1.7.2 Datensatzgruppe laden

Um die so gespeicherte Datensatzgruppe wieder verfügbar zu machen, verwenden Sie die Open-Methode des Recordset-Objekts. Allerdings geben Sie statt eines Tabellen- oder Abfragenamens den Namen der Datei an.

Public Sub DatensatzgruppeEinlesen()

Dim rst As New ADODB.Recordset

rst.Open CurrentProject.Path & "\Personal.xml", , adOpenStatic, _

adLockOptimistic, adCmdFile

Debug.Print rst.RecordCount

Set rst = Nothing

End Sub

Listing 1.30: Einlesen einer Datensatzgruppe aus einer XML-Datei

1.7.3 Ungebundene Recordsets/temporäre Datensatzgruppen verwenden

Unter ADO lassen sich Recordsets ohne Angabe einer Datenherkunft anlegen und zum Speichern von Daten verwenden – also ohne ein Connection-Objekt. Da ein ungebun-denes Recordset keine Datenherkunft hat, besitzt es natürlich auch noch keine Felder. Diese können Sie ganz einfach mit der Append-Methode der Fields-Auflistung des Recordset-Objekts hinzufügen.

Page 31: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1007

Besonderheiten von ADO gegenüber DAO

Anschließend können Sie das Recordset ganz normal verwenden. Ein ungebunde-nes Recordset ist beispielsweise sehr nützlich, wenn Sie größere Datenmengen in Kombinationsfeldern, Listenfeldern oder sogar Datenblättern anzeigen möchten, diese aber nicht in einer Tabelle gespeichert werden sollen.

Die Routine aus dem folgenden Beispiel legt eine Datensatzgruppe mit den beiden Feldern ModulID und Modulname an und fügt alle Module der aktuellen Datenbank hinzu. Anschließend gibt sie alle Einträge der Tabelle im Direktfenster aus.

Public Sub UngebundeneDatensatzgruppe()

Dim rst As ADODB.Recordset

Dim objModul As AccessObject

Dim i As Integer

Set rst = New ADODB.Recordset

rst.Fields.Append "ModulID", adInteger

rst.Fields.Append "Modulname", adVarWChar, 255

rst.Open

For Each objModul In CurrentProject.AllModules

rst.AddNew

rst!ModulID = i

rst!Modulname = objModul.Name

rst.Update

Next objModul

rst.Update

rst.MoveFirst

Do While Not rst.EOF

Debug.Print rst!ModulID, rst!Modulname

rst.MoveNext

Loop

rst.Close

Set rst = Nothing

End Sub

Listing 1.31: Anlegen einer ungebundenen Datensatzgruppe

1.7.4 Disconnected Recordsets

Ein Vorteil von ADO gegenüber DAO ist, dass man ADO-Recordsets auf Basis einer Tabelle erstellen und diese dann »disconnecten« kann – was nichts anderes heißt, als dass man ihre Eigenschaft ActiveConnection auf den Wert Nothing setzt.

Die Verbindung zur Tabelle ist damit unterbrochen, Änderungen am Recordset werden nicht direkt in die Tabelle übertragen.

Page 32: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1008

Zusatzkapitel ADO

Wichtig ist bei dieser Technik, dass Sie das Recordset-Objekt so deklarieren, dass es auch nach dem Einlesen der Daten noch verfügbar ist – also nicht innerhalb der Routine, die das Recordset füllt. Am einfachsten erledigen Sie dies mit einer globalen Variablen, die Sie in einem Standardmodul deklarieren:

Public rstDisconnected As ADODB.Recordset

Es gibt im Wesentlichen zwei Einsatzgebiete für Disconnected Recordsets: nur lesende sowie schreibende und lesende. Bei den nur lesenden Einsätzen gilt es, oft benötigte und nicht zu ändernde Daten nur einmal einzulesen und immer wieder auf diese kopier-ten Werte zuzugreifen. Interessant ist dies vor allem, wenn die Daten über das Netzwerk oder gar das Internet beschafft werden müssen.

Beispiele für solche Einsatzmöglichkeiten sind Konfigurationsdaten, Texte für Mel-dungs fenster oder Fehlermeldungen oder VBA- oder SQL-Ausdrücke wie Funk tio nen und Abfragen.

Der zweite Grund für den Einsatz von Disconnected Recordsets sind Daten, die man vor einer (zwangsweisen) Trennung von der Datenherkunft einliest, bearbeitet und an-schließend wieder speichert.

Da Verbindungen teuer sind, was die Performance angeht, kann es durchaus Sinn ma-chen, diese bei Bedarf zu trennen, um Ressourcen freizugeben.

Disconnected Recordset zum Lesen öffnen

Das erste Beispiel zeigt das Einlesen von Daten, auf die nur lesender Zugriff erfolgt:

Public rstDisconnectedRead As ADODB.Recordset

Public Sub DisconnectedRecordsetsRead()

Set rstDisconnectedRead = New ADODB.Recordset

With rstDisconnectedRead

.ActiveConnection = CurrentProject.Connection

.CursorType = adOpenStatic

.CursorLocation = adUseClient

.LockType = adLockReadOnly

.Source = "SELECT * FROM tblMitarbeiter"

.Open , , , , adCmdText

If Not rstDisconnectedRead Is Nothing Then

Set .ActiveConnection = Nothing

End If

End With

End Sub

Listing 1.32: Einlesen von Daten in ein Disconnected Recordset

Page 33: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1009

Besonderheiten von ADO gegenüber DAO

Aus performancetechnischen Gründen können Sie hier den CursorType auf adOpenStatic und den LockType auf adLockReadOnly einstellen.

Der Zugriff auf die im Recordset rstDisconnectedRead enthaltenen Daten erfolgt genau wie zu Beginn dieses Kapitels beschrieben.

Disconnected Recordset einlesen, ändern und zurückschreiben

Das zweite Beispiel zeigt, wie Sie ein Recordset öffnen, es von der Datenherkunft tren-nen, den Inhalt ändern und das Recordset wieder in die ursprüngliche Tabelle zurück-schreiben.

Mit der folgenden einfachen Routine füllen Sie das Recordset und trennen es von der Datenherkunft:

Public Sub DisconnectedRecordsets()

Set rstDisconnected = New ADODB.Recordset

With rstDisconnected

.ActiveConnection = CurrentProject.Connection

.CursorType = adOpenDynamic

.CursorLocation = adUseClient

.LockType = adLockBatchOptimistic

.Source = "SELECT * FROM tblMitarbeiter"

.Open , , , , adCmdText

If Not rstDisconnected Is Nothing Then

Set .ActiveConnection = Nothing

End If

End With

End Sub

Listing 1.33: Füllen und »disconnecten« eines Recordset-Objekts

Das Recordset ist nun »disconnected«; das heißt, dass Sie unabhängig von der Da ten-her kunft Änderungen darin vornehmen können und diese nicht direkt dort übernommen werden. Eine einfache Änderung nehmen Sie mit folgender Routine vor:

Public Sub DisconnectedRecordsetUpdaten()

If Not rstDisconnected Is Nothing Then

With rstDisconnected

.Find "Nachname = 'Minhorst'"

If Not .EOF = True Then

!Vorname = "Andree"

.Update

End If

End With

Page 34: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1010

Zusatzkapitel ADO

End If

End Sub

Listing 1.34: Ändern des Inhalts eines Disconnected Recordsets

Schauen Sie in der zugrunde liegenden Tabelle nach – der im Recordset geänder-te Da ten satz enthält immer noch denselben Wert wie zuvor. Das ändern Sie nun, in-dem Sie das Re cordset wieder »connecten«. Wichtig ist dabei der Aufruf der Methode UpdateBatch zum Schreiben der Änderungen in die Tabelle – damit speichern Sie alle Änderungen an den enthaltenen Datensätzen:

Public Sub DisconnectedRecordsetWiederVerbinden()

If Not rstDisconnected Is Nothing Then

With rstDisconnected

.ActiveConnection = CurrentProject.Connection

.UpdateBatch

End With

End If

rstDisconnected.Close

Set rstDisconnected = Nothing

End Sub

Listing 1.35: Verbinden des Disconnected Recordsets mit der zugrunde liegenden Datenbank und durchführen der Änderungen

1.7.5 Ereignisse von Datensatzgruppen

Ein sehr interessantes Feature von ADO sind die Ereignisse der einzelnen Objekte wie Connection- oder Recordset-Objekt (siehe Abbildung 1.6). Diese sind gerade in Zu sam-men hang mit der Programmierung mehrschichtiger Anwendungen interessant.

Page 35: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1011

Besonderheiten von ADO gegenüber DAO

Abbildung 1.6: Ereigniseigenschaften von Recordset-Objekten

Sie können die Ereignisse des Connection- und des Recordset-Objekts in einer eigenen Klas se kapseln und entsprechende Prozeduren hinzufügen, die durch die jeweiligen Er-eignisse ausgelöst werden.

Die komplette Kapselklasse soll hier nicht abgedruckt werden, Sie finden diese aber in der Beispieldatenbank ADO.accdb im Klassenmodul clsADORS.

Die folgende Routine instanziert diese Klasse und löst durch einige Datensatzoperationen verschiedene Ereignisse des Connection- und des Recordset-Objekts aus.

Public Sub TestADOEvents()

Dim cADO As New clsADORS

cADO.SetSQL "SELECT * FROM Personal"

DoEvents

cADO.MoveRS 2

DoEvents

cADO.SetSQL "SELECT * FROM Lieferanten"

DoEvents

cADO.MoveRS 7

DoEvents

Set cADO = Nothing

End Sub

Listing 1.36: Instanzieren und Verwenden einer Klasse, die Connection- und Recordset-Ereig-nisse auslöst

Dies jedoch nur als Hinweis darauf, dass ADO durchaus Eigenschaften besitzt, die es von DAO positiv abheben.

Page 36: ADO.pdf - access-entwicklerbuch.deaccess-entwicklerbuch.de/2010/tl_files/downloads/ADO.pdf · String-Eigenschaft Die Verbindungszeichenfolge für die aktuelle Datenbank sieht etwa

1012

Zusatzkapitel ADO

In der Beispieldatenbank ADOEvents.accdb finden Sie ein an ein ADO-Recordset gebun-denes Formular, das die bei der Arbeit mit dem Recordset im Formular zusätzlich ver-fügbaren Ereignisse des Con nec tion- und des Recordset-Objekts erkennen lässt.

BEISPIELDATENBANK

Die Beispieldateien zu diesem Abschnitt finden Sie unter dem Namen ADOEvents.accdb auf www.acciu.de/aeb2010.