Geschrieben von: Christoph Wille
Kategorie: ASP Tricks
This printed page brought to you by AlphaSierraPapa
Eine Komponente, die ein Schattendasein fristet (beziehungsweise gefristet hat) ist das Dictionary Objekt. Dabei kann es sehr nützlich sein. Wer PERL kennt, kennt die assoziativen Arrays - genau das ist ein Dictionary. Für die, die PERL nicht kennen und sich unter einem assoziativen Array nichts vorstellen können, hier die Kurzfassung: ein Schlüsselwert wird verwendet um einen zugewiesenen Wert aufzufinden (zB: eine nette Assoziation ist Flensburg und Polizei).
Also gleich mal zu einem Beispiel zum leichteren Verständnis:
Set myDictionary = CreateObject("Scripting.Dictionary") myDictionary.Add "Flensburg", "Polizei" myDictionary.Add "Kuba", "Zigarren"Damit erstelle ich die Assoziation, die ich dann verwenden kann, um das Teil wieder aufzusuchen:
Response.Write myDictionary.Item("Flensburg")Das Resultat ist wie nicht anders zu erwarten - "Polizei". Vernünftigere Anwendungen wären Benutzername zu Paßwort Zuweisungen oder das Auslesen von Daten aus Tabellen (Primärschlüssel zugewiesen auf zB Nachname).
Damit sind wir auch schon beim Thema, das Verwenden von Dictionaries zusammen mit Recordsets. Da gibt es nämlich eine unheilige Allianz, die ich anhand des folgenden Beispiels erklären werde (ich verwende die pubs Datenbank eines SQL 7 Servers names TOPGUN):
<% Dim oConn, oRS, dicAuthors Set oConn = CreateObject("ADODB.Connection") oConn.ConnectionString = "provider=sqloledb.1;user id=sa;" & _ "password=;initial catalog=pubs;data source=TOPGUN" oConn.Open Set oRS = CreateObject("ADODB.Recordset") oRS.ActiveConnection = oConn oRS.Open "SELECT au_id, au_lname FROM authors" Set dicAuthors = CreateObject("Scripting.Dictionary") while not oRS.EOF dicAuthors.Add oRS(0), oRS(1) oRS.MoveNext wend oRS.Close oConn.Close Dim myKeys, myValues, i myKeys = dicAuthors.Keys myValues = dicAuthors.Items For i = 0 To (dicAuthors.Count -1) Response.Write myKeys(i) & " " & myValues(i) Next %>Eigentlich nichts besonders - außer daß ich statt über ODBC direkt über den OLE-DB Treiber auf den SQL Server zugreife (bringt Geschwindigkeit, weil der ODBC Layer ausgeschaltet wird).
Der eigentliche Haken an der Geschichte ist die while-Schleife:
while not oRS.EOF dicAuthors.Add oRS(0), oRS(1) oRS.MoveNext wendWenn ich das so laufen lasse, dann bekomme ich folgende Fehlermeldung:
Microsoft VBScript runtime error '800a01c9' This key is already associated with an element of this collection /ASPGERMAN/dictionary2recordset.asp, line 21Analyse: Der Fehler tritt bei der zweiten Datensatzzeile auf; der Primärschlüssel au_id ist aber eindeutig - was also ist da passiert? Der Grund liegt im Dictionary selbst - ich kann Objekte zuweisen, und zwar auf den Schlüssel und den Wert (da wird die Adresse und nicht der Wert des Objekts gespeichert). Da ADO aber für oRS.Fields(0) immer das gleiche Field Objekt liefert, ist dessen Adresse im Speicher immer die gleiche - und somit ist beim 2ten Durchlauf der Fehler vorprogrammiert. Der Fehler läßt sich aber leicht beheben:
dicAuthors.Add CStr(oRS(0)), oRS(1)
Damit weise ich den Wert des Objekts (ein String) statt der Adresse des Objekts zu. Wenn ich das Skript jetzt laufen lasse, wird der Fehler allerdings noch um einiges lustiger, und zwar tritt er in der 2ten Zeile des folgenden Codes auf:
For i = 0 To (dicAuthors.Count -1) Response.Write myKeys(i) & " " & myValues(i) NextUnd die Fehlermeldung schulde ich Euch noch:
error '80020009' Exception occurred. /ASPGERMAN/dictionary2recordset.asp, line 32Ich hoffe, einige haben das mit der Objektadresse aufmerksam gelesen - ich habe gesagt, Schlüssel und Wert können ein Objekt aufnehmen, und genau das mache ich immer noch - der Wert ist oRS.Fields(1), mit dem Haken, daß ich das Recordset schon geschlossen habe. Damit ist das Field Objekt schon gelöscht, und wenn ich zugreife, bekomme ich die Zugriffsverletzung. Auch dieser Fehler läßt sich mit der bekannten Methode beseitigen:
dicAuthors.Add CStr(oRS(0)), CStr(oRS(1))
Was wäre passiert, wenn das Recordset noch nicht geschlossen gewesen wäre? Ich hätte einen einzigen Wert bekommen, und zwar den, der in der letzten Zeile gestanden ist. Selbstversuch!
Die Moral von der Geschichte? Dictionaries sind ein mächtiges Werkzeug - sie nehmen alles auf (inklusive Objekten), wie man dann an die Daten wieder herankommt sollte man sich aber bereits vorher überlegt haben. Die Fehler können gemein schwer zu finden sein!
This printed page brought to you by AlphaSierraPapa
Allgemeine MailParser-Klasse mit ASPMail
http:/www.aspheute.com/artikel/20000602.htm
Collections einmal anders: Stacks und Queues
http:/www.aspheute.com/artikel/20000926.htm
Die LookUpTable Komponente
http:/www.aspheute.com/artikel/20010323.htm
Große Datenmengen in Formularfeldern erfolgreich auslesen
http:/www.aspheute.com/artikel/20020430.htm
Klassenauflistungen mit dem Dictionary-Objekt
http:/www.aspheute.com/artikel/20020408.htm
Meta Tags von fremden Seiten parsen
http:/www.aspheute.com/artikel/20010803.htm
©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.