Wie der Fehler auftritt
LotusScript bietet von Haus aus Funktionen an, um zwei NotesDocumentCollections zu vereinigen (Merge), zu schneiden (Intersect) oder voneinander abzuziehen (Subtract). Leider kann dabei ein nicht dokumentierter Fehler auftreten - und das ungünstige daran ist, dass die Fehlermeldung keinen wirklichen Hinweis auf die Ursache gibt:
Invalid object type for method argument (Error code lsERR_NOTES_INVALID_OBJECT = 4336)
Diesen Fehler kann man zum Beispiel mit folgendem Code reproduzieren, wenn man eine volltextindizierte Datenbank mit mindestens je einem Dokument der Masken "Maske1" und "Maske2" hat:
Set coll1 = currentDB().Ftsearch(|[Form] = "Maske1"|, 99)
Set coll2 = currentDB().Ftsearch(|[Form] = "Maske2"|, 99)
Call coll1.Merge(coll2)
Auf einen ungültigen Objekttyp deutet im Debugger auf den ersten Blick nichts hin. Das Argument coll2
ist eine ganz normale NotesDocumentCollection. Nach genauerer Problemanalyse stellte sich heraus, dass der Fehler immer dann auftritt, wenn die Collections sortiert sind, also die Eigenschaft IsSorted = True vorliegt. Das ist beispielsweise bei Resultaten aus der Volltextsuche (so wie im obigen Beispiel) der Fall. Dort lässt sich die Sortierung leider nicht verhindern, aber es geht zumindest aus der Notes/Domino-Hilfe hervor, dass die Ergebnismenge sortiert ist.
Nachdem dieses Problem erkannt und per Workaround behoben war, wunderten wir uns umso mehr, als die gleiche Fehlermeldung einige Zeit später in der gleichen Anwendung, aber an anderer Stelle auftrat. Es stellte sich heraus, dass die FtSearch-Methode - entgegen der Notes/Domino-Hilfe - nicht die einzige ist, die sortierte DocumentCollections erzeugt.
„Sorted collections include all ViewEntryCollections and DocumentCollections created from FTSearch (including DocumentCollections modified by calling the FTSearch method on the collection). All other DocumentCollections are unsorted.“
Ironischerweise stammt dieser Ausschnitt aus der Doku der AddDocument-Methode der NotesDocumentCollection-Klasse. Wie sich herausstellte, sorgt der folgende simple Code mit der AddDocument-Methode ebenfalls für eine sortierte NotesDocumentCollection.
Dabei soll es laut Notes/Domino-Hilfe so sein, dass die IsSorted-Eigenschaft sich durch AddDocument nicht verändert. Startet man mit einer leeren DocumentCollection, gibt es also einen Ausnahmefall
„For sorted collections, the document will be appended. For unsorted collections, the document will be inserted using an internal algorithm.“
Auf diese Weise kommt man also zu einem nicht dokumentierten Fehler durch ein nicht dokumentiertes Verhalten...
Der Lösungscode
Als Lösung haben wir die Operationen letztlich selbt nachgebaut. Merge brauchten wie in unserem Fall nicht und ist sicherlich am leichtesten selbst zu implementieren. Intersect und Subtract haben wir in einer Funktion zusammengefasst. Dabei wird der Eingabe-Parameter dcl
gleichzeitig zur Ausgabe der Ergebnis-Menge genutzt. Der dritte Parameter gibt an, ob man mit dem zweiten Parameter schneiden (isIn2 = True
) oder ihn abziehen (isIn2 = False
) möchte.
Sub FilterDclHardWay(dcl As NotesDocumentCollection, dcl2 As NotesDocumentCollection, isIn2 As Boolean)
Dim doc As NotesDocument
Dim deleteDoc As NotesDocument
Dim dclResult As NotesDocumentCollection
' create empty collection and fill it with docs that fulfill the filter criteria
Set dclResult = dcl.Parent.CreateDocumentCollection()
' go through all docs in dcl
Set doc = dcl.GetFirstDocument
Do Until doc Is Nothing
If isIn2 Then
' intersection: collect all docs that are also in dcl2
If dcl2.Contains(doc) Then
Call dclResult.Adddocument(doc)
End If
Else
' subtraction: collect all docs that are not in dcl2
If Not dcl2.Contains(doc) Then
Call dclResult.Adddocument(doc)
End If
End If
Set deleteDoc = doc
Set doc = dcl.GetNextDocument(doc)
Delete deleteDoc 'only the object will be deleted not the corressponding Notes document (trigger for garbage collector)
Loop
Set dcl = dclResult
End Sub
Haben Sie weitere Fragen zu diesem Thema?
Gerne informieren wir Sie in einem kostenlosen Beratungsgespräch über unsere Angebote. Kontaktieren Sie uns dafür gerne unter +49 4307 900 408 oder vereinbaren Sie hier einen Termin.