Entity Framework (EF) 使いにとっては常識かもしれないが、IQueryable は残念ながらタイプセーフではない。
より正確に言うと、式木の構築はタイプセーフだが、IQueryable.Provider.Execute による式木の実行はタイプセーフでなくなる。
なぜなら、IQueryProvider.Execute の実装が、すべてのメソッドに対応しているわけではないため。
例えば EF の場合、IQueryProvider.Execute は式木から SQL を構築して DB に投げるが、式木内に SQL 変換が考慮されてないメソッドがあった場合、エラーを発生させるしかない。
特に自作メソッドについては対応しようがないため、すべてエラーとなる。
[EF のエラー発生サンプル]
例外的に、Queryable.AsQueryable から生成できる EnumerableQuery は、ほぼタイプセーフになっている。
これの IQueryProvider.Execute の実装は、式木内の Queryable クラスのメソッドを Enumerable クラスの同名のメソッドに置換した後、コンパイルしてラムダ式を作成し、そのまま実行している。
つまり、LINQ to Objects に変換して実行するだけなので、自作メソッドでも何でも使用可能。
上記にないものについては、EntityFunctions や SqlFunctions (SQL Server 専用) を使用する。
LINQ to Entities で自作メソッドを SQL にマップする方法も一応ある。
LINQ to Entities が実際に実行できるかを確認したい場合は、LINQPad がオススメ。
というか競合してるアプリが他にない・・・
より正確に言うと、式木の構築はタイプセーフだが、IQueryable.Provider.Execute による式木の実行はタイプセーフでなくなる。
なぜなら、IQueryProvider.Execute の実装が、すべてのメソッドに対応しているわけではないため。
例えば EF の場合、IQueryProvider.Execute は式木から SQL を構築して DB に投げるが、式木内に SQL 変換が考慮されてないメソッドがあった場合、エラーを発生させるしかない。
特に自作メソッドについては対応しようがないため、すべてエラーとなる。
[EF のエラー発生サンプル]
// テーブル定義
public partial class Customer
{
public string Id { get; set; }
public string Name { get; set; }
}
// 実行処理 (クラス内)
public static void Sample()
{
using( var context = new SampleEntities() ){
var query =
from item in context.Customer
select item.Name.ToUpperInvariant();
// ToUpperInvariant() は LINQ to Entities 未対応
// ToUpper() は対応してる (EF 5.0 で確認)
foreach( var item in query ) Console.WriteLine(item);
// System.NotSupportedException 発生
}
}
例外的に、Queryable.AsQueryable から生成できる EnumerableQuery は、ほぼタイプセーフになっている。
これの IQueryProvider.Execute の実装は、式木内の Queryable クラスのメソッドを Enumerable クラスの同名のメソッドに置換した後、コンパイルしてラムダ式を作成し、そのまま実行している。
つまり、LINQ to Objects に変換して実行するだけなので、自作メソッドでも何でも使用可能。
参考情報
LINQ to Entities で使用可能なメソッドについては、下記参照。上記にないものについては、EntityFunctions や SqlFunctions (SQL Server 専用) を使用する。
LINQ to Entities で自作メソッドを SQL にマップする方法も一応ある。
LINQ to Entities が実際に実行できるかを確認したい場合は、LINQPad がオススメ。
というか競合してるアプリが他にない・・・
0 件のコメント:
コメントを投稿