Blogs

  • Browse Blogs
  • My Blog
  • My Updates

Tags Help

  • View as cloud  | list

Similar Entries

photo

DominoDatabase.HasRo...

Blog:  .Domino Frame...
Peter Presnell
Updated 
No Ratings 0     No Comments 0
photo

@GetFile & @GetFileC...

Blog:  .Domino Frame...
Peter Presnell
Updated 
No Ratings 0     No Comments 0
photo

DominoDocument.XML

Blog:  .Domino Frame...
Peter Presnell
Updated 
No Ratings 0     No Comments 0
photo

Extending a Java Cla...

Blog:  .Domino Frame...
Peter Presnell
Updated 
No Ratings 0     No Comments 0
photo

XSLT Transformation ...

Blog:  .Domino Frame...
Peter Presnell
Updated 
No Ratings 0     Comments 3

Dogear Bookmarks

.Domino Framework

Blog Authors:  Peter Presnell  

Previous |  Main  | Next

Document Collection

Peter Presnell  |     |  Tags:  .dominoframework notesdocumentcollection  |  Comments (2)

The NotesDocumentCollection class has a few attributes that can be rather annoying:-

  1. The Notesdatabase object from which the NotesDocumentCollection is derived must remain in memory.  e.g. A function that returns a NotesDocumentCollection will return an empy object if the NotesDatabase used to create the collection is local to the function.  The NotesDatabase must be either passed as a parameter to the function, or be a global variable.
  2. Documents can only be added to the collection if they are from the same NotesDatabase from which the NotesDocumentCollection was created.

As a way around these issues the following represents an alternate way  to represent a document collection.  This is to store the collection as an array of NotesURLs.  Not only does this technique remove the issues above but it also has the added advantage that it can be easily serialized. e.g. Being an array of strings the values can be easily stored as a field in a Notes document or can be passed back from a Web service.  Of course your application must understand this representation of a document collection and how to process such a collection.

The following function demonstrates how an array of NotesURLs can be created from an Notesdocumentcollection:-

' */ ' * Convert collection to an array of NotesURLs ' */ Function toArray(iDocumentCollection As NotesDocumentCollection) As Variant Dim Doc As NotesDocument Dim Results As Variant Set Doc = iDocumentCollection.GetFirstDocument While Not Doc Is Nothing If Isarray(Results) Then Redim Preserve Results(Ubound(Results)+1) Else Redim Results(0) Results(Ubound(Results)) = Doc.NotesURL$ Set Doc = iDocumentCollection.GetNextDocument(Doc) Wend toArray = Results End Function

I favor the NotesURL format for representing a document because of the ease in which it can be converted to a NotesDocument via the NotesSession.Resolve method.  Unlike a NotesDocumentCollection the array of NotesURLs is enumerated so requires less code to process:-

Forall DocURL In Results Set Doc = Session.Resolve(DocURL$) ' code to process document End Forall

The DominoDocumentCollection class within the .Domino Framework provides a toArray method to convert an existing NotesDocumentCollection.  The constructor of the DominoDocumentCollection class is able to accept an array of NotesURLs to create a NotesDocumentCollection from the NotesURLs.  Note: If documents exist in multiple databases only documents from the first database found are added.

Comments

1 Nathan T Freeman      Permalink "The NotesDatabase must be either passed as a parameter to the function, or be a global variable."

I emailed you the technique that I've been using to deal with this for nearly a decade. It's an approach that has done wonders for the performance of my code in multi-NSF applications.

2 Nathan T Freeman      Permalink Here's what I emailed you. Apparently I don't have a current mail address for you...

There's a trick I do in all of my classes to address this that I'll share with you. I'll usually have an Initialize event that just sets the global session to a new instance. You could also use a factory class to force singleton behavior or something. I'm sure there's all kinds of ways to tune it.

At first, I didn't have the handle limit, but then I found when I was using the cache to run through reporting on multiple NSFs on a server, I'd thrash the memory something fierce.

Anyway, net result is that instead of going NotesSession.getDatabase (server, filepath), I just do globalSession.dbCache(filepath). Then it stays in scope until I need to specifically release it.

I started doing this about 8 years ago, and I've seen order-of-magnitude performance improvements in some cases, because getting db handles isn't just a scoping problem, it's also a REALLY expensive operation.

Dim globalSession as superSession
Private Const DBCACHE_HANDLE_LIMIT = 100
Class superSession
Public dbMap List As String
'A list of specific shorthand maps to other NSFs that might be integral to the application, such as a keywords.nsf lookup.
'You'd populate it with something like dbMap("keywords") = "core\keywords.nsf"
'originally private, but since we're going to use it for our cache lock criteria, we want it setable by the application

Private sess As NotesSession
Private dbCache List As NotesDatabase
Private server As String
Private sourcePath As String
Private dbCount As Integer

Sub New
Set Me.sess = New NotesSession
Set Me.sourceDb = Me.sess.currentDatabase
Me.sourcePath = Replace(Me.sourceDb.filePath, Me.sourceDb.fileName, "")
Me.server = Me.sourceDb.server
End Sub

Property Get dbCache (dbKey As String) As NotesDatabase
Dim targServer As String
Dim targPath As String

If Me.dbCount => DBCACHE_HANDLE_LIMIT Then
Forall cache In Me.dbCache
'why a forall?
'because we want to roll off the oldest one
'if it's in use still, we'll pick it up again, and roll off the next
'that sure beats maintaining some sort of "last accessed" index :-P

'however, if the db is in the dbMap, we'll consider the cache LOCKED
'because if it's an integral enough part of the app to get documented like that,
'then it's probably not a transient member of the cache.

If Not Iselement(dbMap(Listtag(cache))) Then
Erase cache
Exit Forall
End If

'note: if we did want to start maintaining a last accessed index
'it wouldn't be particularly difficult.
End Forall
End If

If Not(Iselement(Me.dbCache(dbKey))) Then 'if it's not in the cache, then we'll get a handle on it
If Instr(dbKey, "!!") Then 'bang bang to specify a different server (I never do this, but it's an option)
targServer = Left$(dbKey, Instr(dbKey, "!!")-1)
targPath = Mid$(dbKey, Instr(dbKey, "!!")+2)
Else
targServer = Me.server
targPath = dbKey
End If

If Iselement(dbMap(dbKey)) Then 'if it's in the map, then we have a shorthand to it.
Set Me.dbCache(dbKey) = Me.sess.getDatabase(targServer, dbMap(targPath))
Else
'first check in the matching directory structure, then go from root...
Set Me.dbCache(dbKey) = Me.p_sess.getDatabase(targServer, Me.sourcePath + targPath)
If Not(Me.dbCache(dbKey).isOpen) Then
Set Me.dbCache(dbKey) = Me.sess.getDatabase(targServer, targPath)
End If
End If
Else
' Print "db" + dbKey + " cached!"
End If

Set dbCache = Me.dbCache(dbKey)
Me.dbCount = Me.dbCount+1
End Property

End Class


Previous |  Main  | Next
Skip to main content link. Accesskey S
IBM Lotus Connections Help Tools About

Tags

A tag is a keyword that is used to categorize an entry. To view the entries with a particular tag, click a tag name or enter a tag in the box.
The tag cloud indicates the frequency of tag use. Popular tags appear darkest. The slider control adjusts how many tags are displayed in the tag cloud.