IViewCursorその3 検索

IViewCursorの逐次アクセス機能およびリストへの追加削除機能がiViewCursorその1のエントリー、
検索機能を利用するために事前準備としてソートが必要というのがIViewCursorその2のエントリーでした。
ということで、今回はやっと検索機能です。
IViewCursorには検索メソッドが3つあります。

  • findFirst
  • findLast
  • findAny

IViewCursorその2に詳細説明があります。

いずれのメソッドもObject型の引数を取ります。
このObjectが検索のキーになっており、例えば{name:"vista"}とすると、検索対象のリストからnameプロパティが"vista"のオブジェクトを探してくれるという感じです。
例で言うと、こんな感じになります。

    public function findTest1():void{
      var list:ArrayCollection = new ArrayCollection();
      list.addItem({name:"a",no:4});
      list.addItem({name:"b",no:3});
      list.addItem({name:"a",no:2});
      list.addItem({name:"b",no:1});
      
      var sort:Sort = new Sort();
      sort.fields=[new SortField("name")];
      list.sort = sort;
      list.refresh();

      for each(var o in list){
       trace(o.name+":"+o.no);
      }
      //検索
      var cursor:IViewCursor = list.createCursor();
      var findSuccess:Boolean = cursor.findFirst({name:"a"});
      if(findSuccess)
       trace("find "+cursor.current.name+":"+cursor.current.no);
      else
       trace("not find");
    }
結果
a:2
a:4
b:3
b:1
find a:2

nameでソート後、nameが"a"のオブジェクトを探します。findFirstなので、ソートされた順に調べて一番最初に見つかったオブジェクトを返します。
nameがa、noが2のオブジェクトが返って来ており、期待通りの結果です。
では、次に検索条件を変えて、noが3のオブジェクトを探してみます。

    public function findTest2():void{
      var list:ArrayCollection = new ArrayCollection();
      list.addItem({name:"a",no:4});
      list.addItem({name:"b",no:3});
      list.addItem({name:"a",no:2});
      list.addItem({name:"b",no:1});
      
      var sort:Sort = new Sort();
      sort.fields=[new SortField("name")];
      list.sort = sort;
      list.refresh();

      for each(var o in list){
       trace(o.name+":"+o.no);
      }
      
      var cursor:IViewCursor = list.createCursor();
      var findSuccess:Boolean = cursor.findFirst({no:3});
      if(findSuccess)
       trace("find "+cursor.current.name+":"+cursor.current.no);
      else
       trace("not find");
    }||<
これを実行するとどうなるかというと
>||
 Error: 検索条件には、最低 1 つのソートフィールド値が含まれている必要があります

というエラーが出てしまいます。
find系メソッドの引数Objectには、Sort時に用いたプロパティが1つは定義されている必要があるようです。
今度はソートフィールドに指定したnameと指定していないnoを使って検索してみます。

    public function findTest3():void{
      var list:ArrayCollection = new ArrayCollection();
      list.addItem({name:"a",no:4});
      list.addItem({name:"b",no:3});
      list.addItem({name:"a",no:2});
      list.addItem({name:"b",no:1});
      
      var sort:Sort = new Sort();
      sort.fields=[new SortField("name")];
      list.sort = sort;
      list.refresh();

      for each(var o in list){
       trace(o.name+":"+o.no);
      }
      
      var cursor:IViewCursor = list.createCursor();
      var findSuccess:Boolean = cursor.findFirst({name:"a",no:4});
      if(findSuccess)
       trace("find "+cursor.current.name+":"+cursor.current.no);
      else
       trace("not find");
    }

結果:

a:2
a:4
b:3
b:1
find a:2

nameがa、noが4のデータが取れるかと思ったら、nameがa、noが2のデータが返って来ました。
つまり、ソートフィールドに指定していないフィールドは検索には使われない、ということのようです。
しかも1つでもソートフィールドに指定したプロパティが入っていた場合は、エラーにならないようです。
次はソートフィールドにnameのnoを指定して検索してみます。

    public function findTest4():void{
      var list:ArrayCollection = new ArrayCollection();
      list.addItem({name:"a",no:4});
      list.addItem({name:"b",no:3});
      list.addItem({name:"a",no:2});
      list.addItem({name:"b",no:1});
      
      var sort:Sort = new Sort();
      sort.fields=[new SortField("name"),new SortField("no")];
      list.sort = sort;
      list.refresh();

      for each(var o in list){
       trace(o.name+":"+o.no);
      }
      
      var cursor:IViewCursor = list.createCursor();
      var findSuccess:Boolean = cursor.findFirst({name:"a",no:4});
      if(findSuccess)
       trace("find "+cursor.current.name+":"+cursor.current.no);
      else
       trace("not find");
    }

結果:

a:2
a:4
b:1
b:3
find a:4

期待通りの値が取れました。
最後にこれを実行してみます。

    public function findTest5():void{
      var list:ArrayCollection = new ArrayCollection();
      list.addItem({name:"a",no:4});
      list.addItem({name:"b",no:3});
      list.addItem({name:"a",no:2});
      list.addItem({name:"b",no:1});
      
      var sort:Sort = new Sort();
      sort.fields=[new SortField("name"),new SortField("no")];
      list.sort = sort;
      list.refresh();

      for each(var o in list){
       trace(o.name+":"+o.no);
      }
      
      var cursor:IViewCursor = list.createCursor();
      var findSuccess:Boolean = cursor.findFirst({name:"a",no:5});
      if(findSuccess)
       trace("find "+cursor.current.name+":"+cursor.current.no);
      else
       trace("not find");
    }

検索キーの一部がどれにもマッチしない条件です。結果は

a:2
a:4
b:1
b:3
not find

となります。ソートフィールドに指定したフィールドをキーにする場合、完全一致しないとデータを返さないようです。

以上を踏まえてIViewCursorの検索に関するまとめですが、

  • 検索を使う場合は事前にソートが必要
  • 検索には、ソートフィールドに指定したフィールドが最低1つ必要
  • ソートフィールドに指定したフィールドのみを使って検索を行う
  • ソートフィールド以外のフィールドを指定しても無視され、検索には利用されない
  • ソートフィールドが複数ある場合、AND条件でデータを探す

という仕様のようです。

検索前にソートが必要ですが、ループを回さなくても目的のオブジェクトをArrayから抜き出せるので、結構便利な機能と思います。