2012年9月9日日曜日

[C#] IEnumerable と IQueryable

http://www.codeproject.com/Articles/231163/IQueryable-Vs-IEnumerable-in-terms-of-LINQ-to-SQL

LINQの結果をIEnumerableとして取得するかIQueryableとして取得するかで発行されるSQLが変わる…?

よくわからないので自分で試してみる。

SchoolClassなる学校のクラスデータが入っているテーブルと、
それに紐つく Scholler(生徒) テーブルを用意。


まずはIEnumerable

        private IEnumerable<SchoolClass> GetSchoolAsEnumarable()
        {
            return from school in db.SchoolClass

                   where school.Grade > 1
                   select school;
        }

        public void ConsoleOutScholler()
        {

             // クラスデータをIEnumerableとして取得
            IEnumerable<SchoolClass> schoolList = GetSchoolAsEnumarable();

            // IEnumerableとして取得したクラスデータに生徒テーブルを結合 
            var schoolerList =
                   from school in schoolList
                   join schooler in db.Schooler
                   on school.ClassID equals schooler.ClassID
                   where school.Grade > 2

                   select schooler;

            foreach (var schooler in schoolerList)
            {
                Console.WriteLine("出席番号:" + schooler.Number + " 名前:" + schooler.Name);
            }
        }


実際にどのようなSQLが発行されているかトレースしてみると…
(データベースはSQLServer)


■発行されたSQL1
SELECT
[Extent1].[ClassID] AS [ClassID],
[Extent1].[Number] AS [Number],
[Extent1].[Name] AS [Name]
FROM [dbo].[Schooler] AS [Extent1]

■発行されたSQL2
SELECT
[Extent1].[ClassID] AS [ClassID],
[Extent1].[Grade] AS [Grade],
[Extent1].[Class] AS [Class]
FROM [dbo].[SchoolClass] AS [Extent1]
WHERE [Extent1].[Grade] > 1


SQLが2つ発行されてる…遅延実行で最終的に一個のSQLになると思ってたんだけど…。
しかも生徒テーブルの方を先に読み込んでいるのがよくわかない件について。
あと school.Grade > 2  がない。えっ。どうやらそちらの条件は.NETの方で絞っているようだ。


次に IQueryable として受け取ってみる

        private IQueryable<SchoolClass> GetSchoolAsQueryable()
        {
            return from school in db.SchoolClass

                   where school.Grade > 1
                   select school;
        }

        public void
ConsoleOutScholler()
        {

            // クラスデータをIQuaryableとして取得
            IQueryable<SchoolClass> schoolList = GetSchoolAsQueryable();

            // IQuaryableとして取得したクラスデータに生徒テーブルを結合
             var schoolerList =
                  from school in schoolList
                   join schooler in db.Schooler
                   on school.ClassID equals schooler.ClassID
                   where school.Grade > 2

                   select schooler;

            foreach (var schooler in schoolerList)
            {
                Console.WriteLine("出席番号:" + schooler.Number + " 名前:" + schooler.Name);
            }
        }


■発行されたSQL
SELECT
[Extent2].[ClassID] AS [ClassID],
[Extent2].[Number] AS [Number],
[Extent2].[Name] AS [Name]
FROM  [dbo].[SchoolClass] AS [Extent1]
INNER JOIN [dbo].[Schooler] AS [Extent2] ON [Extent1].[ClassID] = [Extent2].[ClassID]
WHERE ([Extent1].[Grade] > 1) AND ([Extent1].[Grade] > 2)


SQLが一つになったよ!やったね!
で、なんで IEnumerable のときは2つ発行されてたの?


発行されるSQLが違う理由についてはこのサイト↓にIEnumerableは「pull型」、IQueryableは「外部クエリ」という説明があった。
http://www.atmarkit.co.jp/fdotnet/chushin/roadtolinq_01/roadtolinq_01_03.html

> IEnumerable<T>インターフェイスを使っても外部システムからの
> データ取得はできなくはないのだが、データを全件返すという部分がネックになる

そうなの…。

とにかく LINQ to SQL と LINQ to Entities のときは素直に IQueryable として使いますね?(それでいいのか)

0 件のコメント:

コメントを投稿