Merge, Intersect und Subtract aus NotesDocumentCollection-Klasse führen zu undokumentiertem Fehler 4336

von Christoph,
assono GmbH, Standort Kiel,

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.“

— Notes/Domino-Hilfe (NotesDocumentCollection.AddDocument)

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.

Eine leere NotesDocumentCollection hat die Eigenschaft IsSorted = False. AddDocument setzt allerdings IsSorted auf True.

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.“

— Notes/Domino-Hilfe (NotesDocumentCollection.AddDocument)

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.

Nächste Artikel in dieser Reihe:

Fachbeitrag HCL Notes Entwicklung Für Entwickler

Sie haben Fragen zu diesem Artikel? Kontaktieren Sie uns gerne: blog@assono.de

Sie haben Interesse an diesem Thema?

Gerne bieten wir Ihnen eine individuelle Beratung oder einen Workshop an.

Kontaktieren Sie uns

Weitere interessante Artikel

Sie haben Fragen?

Wenn Sie mehr über unsere Angebote erfahren möchten, können Sie uns jederzeit kontaktieren. Gerne erstellen wir eine individuelle Demo für Sie.

assono GmbH

Standort Kiel (Zentrale)
assono GmbH
Lise-Meitner-Straße 1–7
24223 Schwentinental

Standort Hamburg
assono GmbH
Bornkampsweg 58
22761 Hamburg

Telefonnummern:
Zentrale: +49 4307 900 407
Vertrieb: +49 4307 900 402

E-Mail-Adressen:
kontakt@assono.de
bewerbung@assono.de