8

選択したデータソースからデータを正常に取得する Linq プロバイダーがありますが、フィルター処理された結果セットを取得したので、Linq to Objects が式ツリーの残りの部分を処理できるようにすることです (結合、結合など)。投影など)

私の考えでは、IQueryProvider を含む式定数を ExpressionVisitor を介して結果セット IEnumerable に置き換え、その新しい式を返すことができると考えていました。また、私の IQueryable から IEnumerable のプロバイダーを返します...しかし、これはうまくいかないようです:-(

何か案は?

編集:ここにいくつかの良い答えがありますが、フォームを考えると...

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
          }

私のプロバイダーでは、Customers と Orders から 2 つの結果セットを簡単に取得できます。データが SQL ソースからのものである場合は、SQL Join 構文を作成して渡すだけですが、この場合、データは SQL ソースからのものではないため、コードで結合を行う必要があります...しかし、私が言ったように、私は2つの結果セットを持っており、Linq to Objectsは結合を行うことができます...(そして後で投影)式定数MyProv.Table<Customer>を置き換えるだけで本当にいいでしょうandMyProv.Table<Order>を使用して、プロバイダーに式を処理させます...それは可能ですか? どうやって?List<Customer>List<Order>List<>

4

5 に答える 5

6

前の回答はどちらも機能しますが、AsEnumerable() を使用して IQueryable を IEnumerable にキャストすると読みやすくなります。

// 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 });

編集:

// ... 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
于 2009-03-30T04:40:47.973 に答える
3

私が行ったのは、式ツリーの Queryable<> 定数を具体的な IEnumerable (または .AsQueryable() を介した IQueryable) 結果セットに置き換えることでした...これはおそらく Linq にとってのみ意味のある複雑なトピックです式木ビジターなどにひざまずくプロバイダ・ライター。

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;
        }
    }
}
于 2009-04-28T22:53:44.673 に答える
2

リポジトリ パターンを実装した場合は、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
          }

次に、この記事が示すように、Repository メソッドで 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>();
}
于 2010-07-01T20:18:34.143 に答える
1

誤解していない限り、通常は .ToArray() を linq プロバイダーを実行するポイントで linq メソッドのチェーンに追加するだけです。

例(Linq to SQLを考えてください)

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

したがって、OrderBy() は SQL に変換されますが、Select() は LINQ to Objects です。

于 2009-03-30T01:15:15.613 に答える
0

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

var res = ((IEnumerable<Foo>)dc.Foos
            .Where(x => x.Bla > 0))  // IQueryable
          .Where(y => y.Snag > 0)   // IEnumerable
于 2009-03-30T03:06:37.980 に答える