Expression Tree Compiler が DLINQ のどこで使われているかを書いてみたのですが、非常に分かりにくいことに気づきました。
数回に分けてLINQの重要な部分を説明した後、改めてポストしてみたいと思います。
まず最初に Lambda Expression と Anonymous Method Expression の違いについてです。
決定的な違いとして lambda Expression は
1. 型の推論
2. Expression Tree
のサポートです。 他にもありますが、この二つ違いはクエリ式においてさらに大きな違いとなってきます。
例えは、DLINQ で以下のクエリを書きます。
db.Log = Console.Out;
var q1 = db.Customers.
Where(c => c.City == "London").
Select(c => new {c.City});
var r1 = q1.First();
上のクエリでDLINQがサーバに投げるSQL Queryは
SELECT TOP 1 [t0].[City]
FROM [Customers] AS [t0]
WHERE [t0].[City] = @p0
では、同じようなクエリを Anonymous Method を使って書いてみます。
var q2 = db.Customers.
Where(delegate(Customer c)
{ return c.City == "London"; }).
Select(c => new { c.City });
var r2 = q2.First();
サーバに投げるSQL Queryは
SELECT [t0].[CustomerID], [t0].[CompanyName],
[t0].[ContactName], [t0].[ContactTitle],
[t0].[Address],[t0].[City], [t0].[Region],
[t0].[PostalCode],
[t0].[Country], [t0].[Phone], [t0].[Fax]
FROM [Customers] AS [t0]
もう気づかれた方もいらっしゃると思いますが、2つ目の SQL Query には WHERE がありません。
Anonymous Method を lambda の代わりに使ったことによって
IEnumerable<T> Where<T>(this IEnumerable <T> source,
Func<T, bool> predicate)
の Query Operator が
IQueryable<T> Where<T>(this IQueryable<T> source,
Expression<Func<T, bool>> predicate)
の代わりに使われてしまったためです。 最初に書いたように Anonymous Method は Expression に型変換ではないため IEnumerable<T> の Query Operator が Overload Resolution の解決によって選ばれます。 DLINQ は受け取った Expression Tree (without Where Operator Node) を素直に書き換えるだけです。
もし、Customers Table が1000万件のレコードだったらとしたら。。。 DLINQ はまず1000万件のレコードをメモリに読み込み、メモリでクエリをかける事になってしまいます。 たぶんその前に OutOfMemoryException でアプリケーションが落ちてしまうか、DBA から Database へのアクセスをはずされる事になってしまいますのでお気をつけ下さい。