14

以下は、同じデータを返す2つのクエリです。それ以外のスタイルはどちらが良いかわかりません。

これらのクエリに影響を与える要因は何ですか?あるスタイルを他のスタイルよりも使用する利点は何ですか?

サンプル1

var x = from s in db.Surveys
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
    join q in db.Questions on sq.Question_ID equals q.ID
    join qg in db.Question_Groups on q.ID equals qg.Question_ID
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
    select new { question = sq.Question, status = sq.Status, grp = qg };

サンプル2

var x = db.Surveys.Where(s => s.Type_ID.Equals(typeID) & s.Type.Equals(type))
              .Join(db.Survey_Questions,
                        s => s.ID,
                        sq => sq.Survey_ID,
                        (s, sq) => new
                        {
                            question = sq.Question,
                            status = sq.Status
                        })
              .Join(db.Question_Groups,
                        q => q.question.ID,
                        qg => qg.Question_ID,
                        (q, qg) => new
                        {
                            question = q.question,
                            status = q.status,
                            group = qg
                        }).ToList();
4

8 に答える 8

24

更新: タイトルを修正したので、暴言は無視してください。

質問のタイトルは、コード サンプルとは関係ありません。あなたの質問は、1 つの構文が IEnumerable で、もう 1 つの構文が IQueryable であることを意味していますが、これは正しくありません。あなたのサンプルでdb.Surveysは、​​ が IQueryable の場合、両方のサンプルが IQueryable を使用しています。私は両方の質問に答えようとします。

2 つのコード サンプルは、同じ LINQ クエリを別の方法で記述しただけです (適切に記述されていると仮定します)。The code in sample 1 is just shorthand for the code in sample 2. コンパイラは、両方のサンプルのコードを同じように扱います。int?C# コンパイラがと同じように扱う方法を考えてみてくださいNullable<System.Int32>。C# 言語と VB.Net 言語の両方で、この省略形のクエリ構文が提供されます。他の言語にはこの構文がない可能性があり、サンプル 2 構文を使用する必要があります。実際、他の言語は拡張メソッドやラムダ式をサポートしていない可能性があり、さらに醜い構文を使用する必要があります。


アップデート:

サンダーの例をさらに進めるには、これを書くと(クエリ内包構文):

var surveyNames = from s in db.Surveys select s.Name

コンパイラがその省略形を次のように変換すると思います(拡張メソッドとラムダ式):

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

しかし、実際には拡張メソッドとラムダ式は省略形そのものです。コンパイラは次のようなものを発行します (正確ではありませんが、アイデアを提供するためだけに):

Expression<Func<Survey, string>> selector = delegate(Survey s) { return s.Name; };
IQueryable<string> surveryNames = Queryable.Select(db.Surveys, selector);

クラスSelect()の静的メソッドにすぎないことに注意してください。Queryable.NET 言語がクエリ構文、ラムダ、または拡張メソッドをサポートしていない場合は、コードを自分で作成する必要があります。


あるスタイルを使用する利点は何ですか?

小さなクエリの場合、拡張メソッドをよりコンパクトにすることができます。

var items = source.Where(s => s > 5);

また、拡張メソッドの構文は、条件付き where 句など、より柔軟にすることができます。

var items = source.Where(s => s > 5);

if(smallerThanThen)
    items = items.Where(s => s < 10);
if(even)
    items = items.Where(s => (s % 2) == 0);

return items.OrderBy(s => s);

さらに、いくつかのメソッドは拡張メソッド構文 (Count()、Aggregate()、Take()、Skip()、ToList()、ToArray() など) を介してのみ使用できるため、これらのいずれかを使用すると、両方の構文が混在しないように、通常はこの構文でクエリ全体を記述します。

var floridaCount = source.Count(s => s.State == "FL");

var items = source
            .Where(s => s > 5)
            .Skip(5)
            .Take(3)
            .ToList();

一方、クエリが大きく複雑になると、特にいくつかletの 、groupjoinなどで複雑になり始めると、クエリの理解構文がより明確になります。

最終的には、通常、特定のクエリごとに適切に機能する方を使用します。


更新:タイトルを修正したので、残りは無視してください...

さて、あなたのタイトルについて:LINQに関しては、IEnumerableとIQueryableは非常に似ています。どちらもほとんど同じ拡張メソッド (Select、Where、Count など) を持っていますが、主な (唯一の?) 違いは、IEnumerable がパラメーターFunc<TIn,TOut>として取り、IQueryable がExpression<Func<TIn,TOut>>パラメーターとして取ることです。どちらも同じ方法 (通常はラムバ式) で表現しますが、内部的には完全に異なります。

IEnumerable は、LINQ to Objects への入り口です。LINQ to Objects 拡張メソッドは、任意の IEnumerable (配列、リスト、反復可能なものforeach)で呼び出すことができFunc<TIn,TOut>、コンパイル時に IL に変換され、実行時に通常のメソッド コードのように実行されます。他の一部の LINQ プロバイダーは IEnumerable を使用しているため、実際には舞台裏で LINQ to Objects (LINQ to XML、LINQ to DataSet) を使用していることに注意してください。

IQueryable は、コードを直接実行する代わりに、クエリを調べて変換する必要がある LINQ to SQL、LINQ to Entities、およびその他の LINQ プロバイダーによって使用されます。IQueryable クエリとそのクエリExpression<Func<TIn,TOut>>は、コンパイル時に IL にコンパイルされません。代わりに式ツリーが作成され、実行時に調べることができます。これにより、ステートメントを他のクエリ言語 (T-SQL など) に変換できます。式ツリーは、実行時に Func<TIn,TOut> にコンパイルし、必要に応じて実行できます。

違いを示す例は、OP が SQL Server で LINQ to SQL クエリの一部を実行し、オブジェクトをマネージ コードに取り込み、残りのクエリを LINQ to Objects で実行するこの質問にありますこれを実現するために必要なことは、IQueryable を IEnumerable にキャストし、切り替えが必要な場所に配置することだけです。

于 2009-04-28T05:40:31.770 に答える
4

LINQ はテクノロジの流行語です。

IQueryable は、LINQ で使用される .NET インターフェイスです。

スタイル以外は、両者に違いはありません。お好みのスタイルを使用してください。

私は、長いステートメント (ここに示されているものなど) には最初のスタイルを、非常に短いステートメントには 2 番目のスタイルを好みます。

于 2009-04-28T04:41:54.733 に答える
2

クエリ式と拡張メソッドは、まったく同じことを行う 2 つの方法です。クエリ式は、コンパイル時に拡張メソッドに変換されます。これらは、SQL に慣れている人にとっては単なる構文糖衣です。

これを書くとき:

var surveyNames = from s in db.Surveys select s.Name;

コンパイラはこれを次のように変換します。

IQueryable<string> surveryNames = db.Surveys.Select(s => s.Name);

実際、クエリ式はマーケティング上の理由から作成されたものだと思います。LINQ が開発されたときに目印として機能する SQL のような言語構造であり、実際に使用できるものではありません。C# と SQL を混在させるのではなく、より統一されたコーディング スタイルが得られるため、ほとんどの人は拡張メソッドを直接使用しているようです。

于 2009-04-28T05:31:13.557 に答える
2

最初の例の where 句は、実際には 2 番目のメソッドの Where 句の単なる構文糖衣です。実際、Linq や IQueryable とは関係のない独自のクラスを記述でき、Where メソッドを使用するだけで、そのシンタックス シュガーを使用できます。例えば:

    public class MyClass
    {

        public MyClass Where<T>(Func<MyClass, T> predicate)
        {
            return new MyClass { StringProp = "Hello World" };
        }

        public MyClass Select<T>(Func<MyClass, T> predicate)
        {
            return new MyClass ();
        }



        public string StringProp { get; set; }
    }

これは明らかにばかげた例ですが、stringprop が Hello World に設定された新しい MyClass を返すだけの Where メソッドがあることに注意してください。デモンストレーションするには:

MyClass a = new MyClass();
            var q = from p in a
                    where p.StringProp == "foo" // doesnt matter what we put here, as we're not really checking the predicate
                    select p;
            Console.WriteLine(q.StringProp);

これにより、「Hello World」が出力されます。繰り返しますが、この例は明らかに無意味ですが、「where」構文が Func を受け取るコード内の Where メソッドを探すだけであるという点を証明しています。

于 2009-04-28T04:50:00.580 に答える
1

Sample1はLinqのトップレベルの表現であり、より読みやすく、コンパイル中に式ツリー、つまりSample2に変換されます。

var x = from s in db.Surveys
    join sq in db.Survey_Questions on s.ID equals sq.Survey_ID
    join q in db.Questions on sq.Question_ID equals q.ID
    join qg in db.Question_Groups on q.ID equals qg.Question_ID
    where s.Type_ID.Equals(typeID) & s.Type.Equals(type)
    select new { question = sq.Question, status = sq.Status, grp = qg };

以下のコードを試して、記述されたクエリの式を取得できます

var exp=x.Expression;

式は、クエリがそれほど複雑でない場合に使用されます

于 2009-04-28T06:22:24.633 に答える
1

1./ あなたの質問のタイトルは、あなたが尋ねたものと一致しません。
2./ あなたの質問のタイトルはあまり意味がありません。Linq は Language Integrated Query の略で、一連のテクノロジとプラクティスの包括的な用語です。IQueryable は、Linq を容易にするために一般的に使用されるインターフェイスです。Apples と Oranges
3 を比較しています。/実際の質問について、主な違いはスタイルです。このような複雑なクエリの場合、結果セットの進行が明確に示されるため、私の個人的な好みは 2 番目のバージョンです。

于 2009-04-28T04:48:59.397 に答える
0

言及する価値のあるもう 1 つのポイントは、Linq 拡張メソッドが C# 言語に準拠しているのに対し、クエリ内包はコンパイラに組み込まれているように前処理されていることです。つまり、 .Select(x => の定義に移動できますが、 for はできませんfrom ... where ... select

于 2015-06-23T06:07:00.850 に答える
0

あなたの質問は、「LINQに関して IEnumerable<T> と IQueryable<T> の違いは何ですか」のように表現する方が良いと思います

LINQ クエリは、既定で IQueryable<T> を返します。IQueryable<T> を使用すると、クエリを実行する前に、クエリに他のフィルターまたは "句" を追加できます。

LINQ クエリ (最初の例) とメソッド チェーンを使用する LINQ (2 番目の例) は、異なる構文で同じ結果を生成します。

LINQ クエリを LINQ メソッド チェーンとして記述することも、その逆も可能です。それは本当にあなたの好みに依存します。

@Lucas: 違いは、IEnumerable<T> がメモリ内クエリを実行し、IQueryable<T> がメモリ不足を実行することです。つまり、foreachイテレータに入ると IEnumerable を使用し、拡張メソッドまたは LINQ シナタックスを使用してクエリを作成するfrom o in objectときは、IQueryable<T> を作成します。IQueryable<T> は、列挙子に触れるとすぐに実行されます。

于 2009-04-28T04:43:06.010 に答える