web-dev-qa-db-ja.com

LINQ to Entity Frameworkオブジェクトの述語を使用する方法

データアクセスレイヤーのEntity FrameworkオブジェクトのLINQ to Entitiesを使用しています。

私の目標は、メモリ内の結果にフィルタリングロジックを適用せずに、データベースからできる限りフィルタリングすることです。

そのために、ビジネスロジック層は述語をデータアクセス層に渡します。

というのは

Func<MyEntity, bool>

したがって、この述部を直接使用すると、

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.Where(x => isMatched(x));
}

例外が発生しています

[System.NotSupportedException] --- {「LINQ式ノードタイプ「Invoke」は、LINQ to Entitiesではサポートされていません。」}

の解決策は、questionからAsExpandable()メソッドを使用することを示唆していることLINQKit ライブラリ。

しかし、再び、使用して

public IQueryable<MyEntity> GetAllMatchedEntities(Func<MyEntity, Boolean> isMatched)
{
    return qry = _Context.MyEntities.AsExpandable().Where(x => isMatched(x));
}

例外が発生しています

タイプ 'System.Linq.Expressions.FieldExpression'のオブジェクトをタイプ 'System.Linq.Expressions.LambdaExpression'にキャストできません

エンティティフレームワークオブジェクトのLINQ to Entitiesクエリで述語を使用して、SQLステートメントに正しく変換する方法はありますか。

ありがとうございました。

22
bairog

これを行うためにLinqKitは必要ありません。使用することを忘れないでください

Expression<Func<MyEntity, bool>>

の代わりに

Func<MyEntity, bool>

このようなもの:

public IQueryable<MyEntity> GetAllMatchedEntities(Expression<Func<MyEntity, Boolean>> predicate)
{
    return _Context.MyEntities.Where(predicate);
}

Linq to EntitiesはラムダをSQLに変換する必要があるため、Expressionを使用する必要があります。

Funcを使用すると、ラムダはILにコンパイルされますが、Expressionを使用すると、Linq to Entitiesが横断および変換できる式ツリーになります。

これは、Linq to Entitiesが理解できる式で機能します。

失敗し続ける場合、式は、Linq to EntitiesがSQLに変換できないことを行います。その場合、LinqKitが役立つとは思わない。

編集:

変換は必要ありません。 ExpressionパラメーターでメソッドGetAllMatchedEntitiesを定義し、Funcパラメーターで使用するのと同じ方法で使用します。コンパイラが残りを行います。

GetAllMatchedEntitiesを使用できる方法は3つあります。

1)インラインラムダ式の場合:

this.GetAllMatchedEntities(x => x.Age > 18)

2)式をフィールドとして定義します(変数にすることもできます)

private readonly Expression<Func<MyEntity, bool>> IsMatch = x => x.Age > 18;
...then use it
this.GetAllMatchedEntities(IsMatch)

3)式を手動で作成できます。ダウンサイズはより多くのコードであり、コンパイル時のチェックを見逃します。

public Expression<Func<MyEntity, bool>>  IsMatchedExpression()
{
    var parameterExpression = Expression.Parameter(typeof (MyEntity));
    var propertyOrField = Expression.PropertyOrField(parameterExpression, "Age");
    var binaryExpression = Expression.GreaterThan(propertyOrField, Expression.Constant(18));
    return Expression.Lambda<Func<MyEntity, bool>>(binaryExpression, parameterExpression);
}
44
andres.chort

Linq to Entitiesで使用されるメソッドは、動作するためにLinqプロバイダーによって正規にマッピングされる必要があります。 Linqプロバイダー(あなたの場合はEF)は、述語を内部メソッドにマップできなかったため、エラーをスローしました。

LINQシナリオの場合、Entity Frameworkに対するクエリには、標準関数を介して特定のCLRメソッドを基になるデータソースのメソッドにマッピングすることが含まれます。正規関数に明示的にマップされていないLINQ to Entitiesクエリでメソッドを呼び出すと、ランタイムNotSupportedException例外がスローされます

ソース:CLR Method to Canonical Function Mapping( http://msdn.Microsoft.com/en-us/library/bb738681.aspx

[〜#〜] [〜#〜](-#〜]にマッピングされているメソッドを取得してLinq式にチェーンするか、または手順。ただし、EFがすべてのCLRをサポートするまで、回避策を見つける必要があります。

プラス面として、各リリースは正規リストにもう少し追加するようです。

回避策として読む価値がある: http://msdn.Microsoft.com/en-us/library/dd456857.aspx

3
Gayot Fow