前回のLocationFinderクラスによって、検索条件となる文字列の一覧が得られた。この検索条件をTerraServer WCFインターフェイスを使用して、サービスに送信する。すると、結果レコードがPlaceクラスに入れられて返される。結果が複数のレコードとなる可能性があり、WCFメソッドの戻り値はPlaceの配列で定義されている。
とうとう結果が得られたのだ。これをそのまま返せばよい。が、しかし、今まで扱ってきたのは、あくまでIQueryableによるLINQクエリだ。IEnumerableならそのまま返せばよい(配列はIEnumerableを実装しているので)が、少なくともIQueryableでなければならない。
であれば話は簡単だ。配列をAsQueryableすれば良い。
// Get the place name(s) to query the Web service with. LocationFinder lf = new LocationFinder(lambdaExpression.Body); List<string> locations = lf.Locations; if (locations.Count == 0) throw new InvalidQueryException("You must specify at least one place name in your query."); // Call the Web service and get the results. Place[] places = WebServiceHelper.GetPlacesFromTerraServer(locations); // Copy the IEnumerable places to an IQueryable. IQueryable<Place> queryablePlaces = places.AsQueryable<Place>();
結果のIQueryableは、もはやTerraServer LINQプロバイダーの手を離れ、LINQ to ObjectsのLINQプロバイダーが処理を行うようになる。
まだ終わりではない
最初にInnerMostWhereFinderクラスで、最も内側のWhereを探索した事を覚えているだろうか? いま、一息ついたところだが、ここまでの処理で実現したのは、その「最も内側のWhere条件」だ。その外側のLINQクエリは放置されている。これを処理しなければならない。
しかし、前述のようにもうTerraServerは関係ないため、配列をAsQueryableした結果を使って続きのクエリを実行させる必要がある。これを行わせるのが、「ExpressionTreeModifier」クラスだ。このクラスもExpressionVisitorを継承している。やっていることは単純だ。TerraServerのコンテキストクラスのインスタンスを、上記配列をAsQueryableしたものに挿げ替える。
生成されたExpressionは、もはやTerraServerコンテキストを含まない。かつ、サービスから得られた結果を配列で含んでいるため、Expressionツリー全体がLINQ to Objectsで評価可能な状態にある。CreateQueryを呼び出してIQueryableを生成すれば、そのインスタンスはLINQ to ObjectsのLINQプロバイダーが管理する。
こうして、LINQ to TerraServerが完成した。