GetDocumentByUNID doesn't return "Nothing"?

Hi all,

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

Wend

Print “Removed " & count & " unassociated document profiles…”

Subject: GetDocumentByUNID doesn’t return “Nothing”?

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!

    ...

Hope that helps.

Subject: RE: GetDocumentByUNID doesn’t return “Nothing”?

Cheers Ben,

I will try this too, although the same error occurs if the profile document is created, but then the main document is not even saved.

Craig.

Subject: FYI: 6.5.4 documentation is updated

I have 6.5.4 and my Designer Help has been updated to show that it raises an error. No mention of previous Nothing behavior.

Subject: GetDocumentByUNID doesn’t return “Nothing”?

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.

Subject: RE: GetDocumentByUNID doesn’t return “Nothing”?

OK, but the help certainly states :

b>]Return value/b>]
notesDocument
NotesDocument. The document with the specified universal ID. Returns Nothing if
a match is not found.

I will try making it …(0), although the method returns a document perfectly
if the main document exists.

Craig.

Subject: RE: GetDocumentByUNID doesn’t return “Nothing”?

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 :wink:

Let’s know if this solves your problem.

Subject: RE: GetDocumentByUNID doesn’t return “Nothing”?

Yes, I am looping through a collection of profile documents which I created from other documents using their unique ID as the key…

e.g.

@SetProfileField( “DocProfile”; “Field”; “Value”; @Text(@DocumentUniqueID));

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!! :¬)

Cheers!

Craig.

Subject: BUG ! GetDocumentByUNID doesn’t return “Nothing”?

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	

Exit Sub

ErrorRoutine:

Msgbox "Error" + Cstr(Err) + " : " + Cstr(Error) + " : " + Cstr(Erl)

Exit Sub

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

End Function

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.

Subject: *Good point

Subject: RE: *Good point

I’d still rather have exceptions to catch ('e said, refering obliquely to Ned Batchelder’s blog), but one takes what one can get.

Subject: *And I’d rather have it just return Nothing instead of raising error, but obviously there are different opinions on this.

Subject: Returning an error AND setting the Doc to nothing (=old and documented behavior) should satisfy us all.