2009-03-30 7 views
7

私は、選択したデータソースから正常にデータを取得するLinqプロバイダを持っていますが、今はフィルタリングされた結果セットを持っています私は、IQueryProviderを含む式定数を、ExpressionVisitorを介して結果セットIEnumerableに置き換えてから、次に、ExpressionVisitorを使用して結果セットIEnumerableを置き換えることができたと思っていました。新しい表現を返します。また、私のIQueryableからのIEnumerableのプロバイダを返す...しかし、これはIQueryableクエリの一部を実行し、残りの部分をオブジェクトのLinqに延期する

任意のアイデアの

編集:-(動作していないよう:?...フォーム与えられ、ここで いくつかの良い答えが、

var qry = from c in MyProv.Table<Customer>() 
      Join o in MyProv.Table<Order>() on c.OrderID equals o.ID 
      select new 
      { 
      CustID = c.ID, 
      OrderID = o.ID 
      } 

私のプロバイダでは、顧客と注文の2つの結果セットを簡単に取り戻すことができます。データがSQLソースからのものであれば、SQL結合構文を作成して渡しますが、データは私は2つの結果セットを持っていると言ったように、オブジェクトへのLinqは、参加することができます...(そして、後でプロジェクション)では、式定数MyProv.Table<Customer>MyProv.Table<Order>List<Customer>List<Order>に置き換えて、List<>プロバイダが式を処理できるようにするのは本当にうれしいことです...可能ですか?どうやって?

答えて

3

私は後に照会可能<を交換した事の種類>式ツリー内の一定のコンクリートのIEnumerable(またはIQueryableを経由して.AsQueryable())result set ...これはおそらく、表現木の訪問者などで深刻なLinq Providerの作家には意味をなさない複雑なトピックです。

msdnウォークスルーで何かを行うスニペットが見つかりました私は後に、これが私の進むべき道を与えていますどのような...

using System; 
using System.Linq; 
using System.Linq.Expressions; 

namespace LinqToTerraServerProvider 
{ 
    internal class ExpressionTreeModifier : ExpressionVisitor 
    { 
     private IQueryable<Place> queryablePlaces; 

     internal ExpressionTreeModifier(IQueryable<Place> places) 
     { 
      this.queryablePlaces = places; 
     } 

     internal Expression CopyAndModify(Expression expression) 
     { 
      return this.Visit(expression); 
     } 

     protected override Expression VisitConstant(ConstantExpression c) 
     { 
      // Replace the constant QueryableTerraServerData arg with the queryable Place collection. 
      if (c.Type == typeof(QueryableTerraServerData<Place>)) 
       return Expression.Constant(this.queryablePlaces); 
      else 
       return c; 
     } 
    } 
} 
+0

私は私の膝からお願いします - 深い式ツリーの訪問者に。 :)これはまさに私が必要としたものです – Rik

1

私が誤解していない限り、私は一般的にlinqメソッドのチェーン内でlinqプロバイダを実行させたいところに.ToArray()を追加します。

例えば)ので、[並べ替えて

var result = datacontext.Table 
    .Where(x => x.Prop == val) 
    .OrderBy(x => x.Prop2) 
    .ToArray() 
    .Select(x => new {CoolProperty = x.Prop, OtherProperty = x.Prop2}); 

を((LINQ to SQLは思う)SQLに変換されますが、選択は()オブジェクトにLINQです。

0

ロブの答えは良いですが、完全な列挙を強制します。あなたは、拡張メソッドの構文と遅延評価を維持するためにキャストすることができます:

var res = ((IEnumerable<Foo>)dc.Foos 
      .Where(x => x.Bla > 0)) // IQueryable 
      .Where(y => y.Snag > 0) // IEnumerable 
5

前の回答の両方が動作していますが、IEnumerableをへのIQueryableをキャストするAsEnumerable()を使用している場合、それはより良い読み:

// Using Bob's code... 
var result = datacontext.Table 
    .Where(x => x.Prop == val) 
    .OrderBy(x => x.Prop2) 
    .AsEnumerable() // <---- anything after this is done by LINQ to Objects 
    .Select(x => new { CoolProperty = x.Prop, OtherProperty = x.Prop2 }); 

EDIT:

// ... or MichaelGG's 
var res = dc.Foos 
      .Where(x => x.Bla > 0) // uses IQueryable provider 
      .AsEnumerable() 
      .Where(y => y.Snag > 0); // IEnumerable, uses LINQ to Objects 
1

あなたはあなただけ離れて背中と抽象テーブルをのIQueryableを提供して逃げることができリポジトリパターンを実装した場合。

例:

var qry = from c in MyProv.Repository<Customer>() 
      Join o in MyProv.Repository<Order>() on c.OrderID equals o.ID 
      select new 
      { 
      CustID = c.ID, 
      OrderID = o.ID 
      } 

、その後、ちょうどthis articleが示すだけのようなあなたのリポジトリ方法でのIQueryableパターンをモデル化するために、プロバイダを構築します。

このようにして、必要なものをすべて使用するプロバイダを作成できます。 LINQ 2 SQLプロバイダを持つか、単体テスト用のメモリ内プロバイダを作成できます。

LINQ 2 SQLプロバイダのリポジトリ方法は、次のようになります

public IQueryable<T> Repository<T>() where T : class 
{ 
    ITable table = _context.GetTable(typeof(T)); 
    return table.Cast<T>(); 
} 
+0

非常に興味深い、私はこれを周り、今週末遊ぶでしょう。 –

関連する問題