2011-06-21 8 views
2

私は、特定の条件に一致するテーブルの特定の行のデータベースとローカルメモリの両方を調べるためのEF4.1の汎用メソッドを構築しようとしています。LINQ to Entitiesで匿名メソッドを実行するにはどうすればよいですか?

これまでのところ、これは私が持っているものです。

これは発信者です。

dbEntities.MyTables.LocalAndDb(delegate(MyTable s) 
       { return s.Description.Contains("test"); }); 

これは、問題は、この行であるLocalAndDb

public static object LocalAndDb<T>(this DbSet<T> myTable, Func<T, bool> function) where T : class 
{ 
    // look in local 
    var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault() 
    // if not exist, look in the database 
    if (item == null) 
    { 
     Expression<Func<T, bool>> predicate = (u) => function(u); 
     item = myTable.Where(predicate).FirstOrDefault(); 
    } 
    return item; 
} 

です。

item = myTable.Where(predicate).FirstOrDefault(); 

データベースを呼び出すと、このエラーがスローされます。

"LINQ表現ノードタイプ 'Invoke'は、LINQ to Entitiesではサポートされていません。

私は匿名メソッドを渡しているため、これをSQLに変換する方法がわからないためです。私はそれをExpressionオブジェクトに変換することはそのトリックを行うと思ったが、まだそれは私のために働いていない。

匿名メソッドをLINQでSQLに変換できるようにするには、何が必要ですか?当然の

public static object LocalAndDb<T>(this DbSet<T> myTable, 
    Expression<Func<T, bool>> expr) where T : class { 
    // ... 
    if (item == null) { 
     item = myTable.Where(expr).FirstOrDefault(); 
    } 
    return item; 
} 

次に、:

答えて

4

(エンティティへのLINQは、コードを解析し、S​​QLにそれを変換することができるように)、この作業を行うには、あなたが式ツリーとしてLocalAndDbにラムダ式を渡す必要があります問題は、メモリ内のデータをチェックするときに式ツリーを実行できないことです。これを解決する1つの方法は、Expression<T>Compileメソッドを使用することですが、それは少し効率が悪いでしょう(シナリオによって異なります)。

別のオプションは、単に機能と式ツリーの両方としての条件を渡すことです:

public static object LocalAndDb<T>(this DbSet<T> myTable, 
    Func<T, boo> function, Expression<Func<T, bool>> expr) where T : class { 
    var item = myTable.Local.Where(o => function((T)o)).FirstOrDefault(); 
    if (item == null) { 
     item = myTable.Where(expr).FirstOrDefault(); 
    } 
    return item; 
} 

table.LocalAndDb(t => t.Foo > 10, t => t.Foo > 10); 

これは少し醜いですが、それは実行時に非効率的なコンパイルを必要としません。少し洗練されたソリューションが必要な場合は、事前にコンパイルされた関数を保持するために独自の型を定義することができます:

class Precompiled<T1, T2> { 
    public Precompiled(Expression<Func<T1, T2>> expr) { 
    this.Expression = expr; 
    this.Function = expr.Compile(); 
    } 
    public Expression<Func<T1,T2>> Expression { get; private set; } 
    public Func<T1,T2> Function { get; private set; } 
} 
+0

コンパイル済み!ありがとう、ありがとう!私はEFに関しては完全な初心者です。しかし、私は今、パフォーマンスの面でいくつかの研究を行います。これは、メソッド内、シグネチャ内、またはプリコンパイルされたコンストラクタ内のいずれであっても、式を「コンパイル」するとパフォーマンスに影響すると言いますか? – Diskdrive

+0

@stickman - 'Precompiled'クラスのアイデアは、一度だけ(' Compile'を一度呼び出すように)簡単に構築し、その結果を 'LocalAndDb'を複数回呼び出す際に繰り返し使用することで、式isn '呼び出しごとに再コンパイルされます。 –

+0

それはきれいです。再度、感謝します! – Diskdrive

関連する問題