In my database, documents can have options set against them which are held in a profile document keyed on the main document’s unique ID. These options could be created, and then the main doc not saved, or the main doc could be deleted. Either way, I would have profile docs floating around which would be doing nothing.
I have an agent which is supposed to go through a collection of profile documents, and check to see if the main document still exists and if it doesn’t delete the profile document. I am checking for the main document using db.GetDocumentByUNID, but if the document doesn’t exists I just get an error “invalid universal id” instead of Nothing as I would expect (and as per the help). If the main document does still exist, it is found correctly!!
Anyone else have this issue?
Craig.
Set session = New NotesSession
Set db = session.CurrentDatabase
count = 0
Set col = db.GetProfileDocCollection( “DocProfile” )
Set doc = col.GetFirstDocument
While Not( doc Is Nothing )
Set checkdoc = db.GetDocumentByUNID( doc.Key )
If checkdoc Is Nothing Then Set deldoc = doc
Set doc = col.GetNextDocument( doc )
If Not( deldoc Is Nothing ) Then
count = count + 1
Call deldoc.Remove( True )
End If
Hmmm… your code may be stumbling across a “stub” document. Rather than returning Nothing, your code gets a handle on a doc, but it has no items because it’s a deletion stub. You could test for this by doing something like:
Set doc = db.GetDocumentByUNID(strUNID)
If Not(doc Is Nothing) Then
If doc.isValid = False Then
' // This is a stub!
...
My understanding is that notesDatabase.getDocumentByUnid() does NOT return Nothing if an invalid or non-existing UNID is passed to it. Instead, it raises a runtime error, which you can catch.
You can massage your code to effectively return Nothing, like so:
set checkdoc = nothing
on error resume next ’ ignores runtime error
Set checkdoc = db.GetDocumentByUNID( doc.Key )
on error goto 0 ’ re-enable runtime error reporting
’ at this point, checkdoc will be Nothing if doc.key is invalid or points to a non-existing document
If checkdoc Is Nothing Then …
Mind you, my guess is that you need to change the reference to doc.Key to doc.Key(0) to make the code work, since doc.Key returns an array, not a String.
You are right w.r.t. the Help. But it definitely behaves the other way in R5, and in any case, it will catch any runtime errors during getDocumentByUnid and return Nothing.
Another thing that confuses me, is that you use doc.Key at all. This is a pre-defined property used for profile documents (see Designer Help for NotesDocument). If you need the value of a Key field, use doc.getItemValue(“Key”)(0) - or are you intentionally using this property? I’m surprised it works at all
I am checking that the main document the profile document refers too still exists, so doc.Key (the predefined property) should contain the main documents unique doc ID!
I think you are right, and I am going to have to just trap the error!! :¬)
That’s a bug in my opinion. Under R4.5/R5.0.9, it returned nothing. Under 6.0x it should do the same, according to the “help”…
→ It’s clear that it’s not set back to nothing anymore, and returns the previous document-object.
Script To Test:
On Error Goto doerror
Dim s As New notessession
Dim db As notesdatabase
Dim doc As NotesDocument
Set db = s.CurrentDatabase
Set doc = db.AllDocuments.GetFirstDocument
Print "UNID=" & doc.UniversalID
On Error Resume Next 'avoid the error raising
'a random ID here for test
Set doc = db.GetDocumentByUNID("3707F499C9601E53C1256D5D004DF5C9")
On Error Goto doerror
Print "IsNothing=" & (doc Is Nothing)
Print "UNID=" & doc.UniversalID
Goto ende
doError:
On Error Resume Next
Print "ERR"
Resume ende
ende:
Prints the following:
UNID=A9770D0BA6EE0F17C1256B98004DDD61
IsNothing=False
UNID=A9770D0BA6EE0F17C1256B98004DDD61
Thanks to this, a mass of our data import routines imported data to a wrong document, instead of discarding the data if the document would return nothing.
So, my job for the next days is clear: insert a set doc = nothing before each getDocumentByUNID-Call. Very nice, I just waited for that … Not to talk about the correcting the wrong data the bug caused.
How could this pass the quality control (do they have something like this?) ?
I’m really disappointed. You can’t even count on these basic functions anymore these days.
Subject: GetDocumentByUNID doesn’t return “Nothing” and doesn’t raise an error
Hello,I’ve just run across this issue and I wouldn’t be posting if I’d seen anything in the fix list. I was writing a little agent to correct a problem with the Discussion Thread view in a 4.6 mailbox (servers and clients are running 6.51 under W2003 or NT or XP) (the initial pb is that mails that are replies to a mail not originally sent to the mailbox don’t appear in the DT view because there’s no parent…)
My reading of the help on GetDocumentByUNID was that an invalid UNID would raise error 4091 : to quote : “Not matching the UNID to a document in the database raises lsERR_NOTES_BAD_UNID (4091).”
I was therefore not even expecting to use “Is Nothing” but to vector straight off into an error process.
My original script looked like this, the idea was to raise an error when the parent document was missing and remove the $REF field from the orphan in the error processing :
On Error 4091 Goto procERR
Set db = s.CurrentDatabase
Set coll = db.UnprocessedDocuments
For i = 1 To coll.Count
Set doc = coll.GetNthDocument(i)
strUNID = doc.ParentDocumentUNID
If strUNID <> "" Then 'this is a reply and may be an orphan
Set docParent = db.GetDocumentByUNID(strUNID) 'this should have raised an error 4091 if parent is missing
End If
Next
Exit Sub
procERR:
Call doc.RemoveItem("$REF")
Call doc.Save(True,False)
Resume Next
Instead of getting an error, docParent gets a sort of pseudo-doc with dates identical to doc and no items. My workaround was to look at the docParent size… if zero, it’s a ghost !
However, this only seems to happen in particular circumstances. If I stop the script before the If and enter another inexistent value for strUNID then I get an error all right !
Subject: RE: GetDocumentByUNID doesn’t return “Nothing” and doesn’t raise an error
On Error Goto ErrorRoutine
Dim s As New NotesSession
Dim db As NotesDatabase
Set db = s.CurrentDatabase
Dim doc As NotesDocument
Dim Unid$
Unid$ = YOURKEY$
found% = checkUNIDdoc%(db, Unid$)
If Not found% Then
Msgbox "Document not found"
Else
Msgbox "Document found"
End If
Function checkUNIDdoc%(db As NotesDatabase, Unid$)
On Error Resume Next
Dim doc As NotesDocument
checkUNIDdoc% = False
Err = 0
Set doc = db.GetDocumentByUNID(Unid$)
If Err = 0 Then
checkUNIDdoc% = True
End If
Err = 0
Subject: Isn’t your proposed workaround the wrong approach?
You say:
<<So, my job for the next days is clear: insert a set doc = nothing before each getDocumentByUNID-Call. Very nice, I just waited for that … Not to talk about the correcting the wrong data the bug caused.>>
But wouldn’t the more logical approach be to actually use the On Error to clear this out? I am not even clear this is a bug. You put in the line “On Error Resume Next”, which basically means “ignore this error”, but wouldn’t it make more sense to have “On Error Goto doError” and then have do Error be more like
doError:
Set doc = Nothing
Resume next
This would only do the setting the doc to Nothing when an error is raised.
Subject: RE: Isn’t your proposed workaround the wrong approach?
The “doError” block has another function in our scripts, it logs errors to a database. Since we don’t want an error to be raised in the condition that getDocumentByUNID returns nothing, the “On Error resume next” is a good way to achive this. Well - as i said, it worked for old Domino/Notes-Releases this way. I’m just angry that they changed such a basic behavior without a notice.
Subject: RE: Isn’t your proposed workaround the wrong approach?
Then use:
On Error 4091 Goto BadUnidHandler
or some such. Not surprisingly, error 4091 is lsERR_NOTES_BAD_UNID, and will be returned when an invalid/nonexistant UNID is used in GetDocumentByUNID.