2010年1月30日土曜日

@DbLookup 式を LotusScript へ変換する

既存アプリケーションを変更する際、式言語ではできないことを実現するため LotusScript へ変換することがあります。

今回は思い出したくない過去の失敗事例を思い出してしまったので、ここにご紹介します。

変換前の式には @DbLookup は下のような式です。

Category2 := @DbLookup("": "NoCache"; @DbName; "test"; Category1; "Category2")

これを Lotus Script へ変換するとします。Category1 はフィールド名です。
Dim ws As New NotesUIWorkspace
Dim doc As NotesDocument
Dim vw As NotesView
Dim dc As NotesDocumentCollection
Dim category2 As Variant
Dim tmpKey As String, init(0) As String

Set vw = ws.CurrentDatabase.Database.GetView( "test" )
set tmpKey = ws.CurrentDocument.Document.Category1(0)
Set dc = vw.GetAllDocumentsByKey( tmpKey, True )
If dc.Count > 0 Then
  category2 = init
  Set doc = dc.GetFirstDocument
  While Not ( doc Is Nothing )
    Category2 = Arrayappend( Category2, doc.Category2 )
    Set doc = dc.GetNextDocument( doc )
  Wend
  category2 = Fulltrim( Category2 )
End If
一見何の問題ないように見えるこのプログラム...実は大きな落とし穴があったんです。

見落としだったのですが...フォーム上の Category1 は"複数値も可"が有効なフィールドでした。

@DbLookup のキーには複数値を設定できます。
複数値で検索した場合、指定した複数の値に一致するすべての値を一度に取り出します。

そのため上記の Category(0) といったように配列の0番目だけを取り出すのではなく、
配列のすべての要素を検索のキーとして指定する必要があります。

ここで注意したいのは、GetAllDocumentsByKey で指定するキーです。

このキーは配列でもよいのですが、@DbLookup では最初のソートされた列だけを対象に検索してくれるのに対して、GetAllDocumentsByKey では複数のソート列を対象にして検索します。

同じように複数値を指定しても検索結果が違うのです。

つまり、次のように変換するのが正しかったのです。
<...宣言は省略...>
Set vw = ws.CurrentDatabase.Database.GetView( "test" )
Category2 = init
Forall o In ws.CurrentDocument.Document.Category1
  Set dc = vw.GetAllDocumentsByKey( o, True )
  If dc.Count > 0 Then
    Set doc = dc.GetFirstDocument
    While Not ( doc Is Nothing )
      Category2 = Arrayappend( Category2, doc.Category2 )
      Set doc = dc.GetNextDocument( doc )
    Wend
  End If
End Forall
Category2 = Fulltrim( Category2 )

2 件のコメント:

  1. ソボクな疑問
    Set vw = ws.CurrentDatabase.Database.GetView( "test" )
    の部分は、
    set db = ws.CurrentDatabase
    set vw = db.getview("test")
    と書く場合もあるとおもうのですが、dbを再利用する場合、
    実行パフォーマンス上"set db"しておいた方が良いのか、
    "set db"していなくても変わらないのかご存じですか?
    基本的すぎて、申し訳ないのですが...

    返信削除
  2. 体感速度を重視するなら、ほとんど変わらないと思います。

    ただ(計ったことがないのでよくわかりませんが)db オブジェクトを新規に作成する場合、それだけメモリを消費すると仮定した場合、"set db" しないほうがパフォーマンスはいいかもしれませんね。

    機会があればエージェント・プロファイルで調べてみたいと思います。

    返信削除