2016-11-01 15 views
1

EFコアの動的検索を作成しようとしています。リフレクションでのパフォーマンスの問題

foreach (var i in vm.SearchProperties) 
{ 
    if (result == null) 
    result = db.MyTable.Where(x => x.GetType().GetProperty(i).GetValue(x, null).ToString().ToLower().StartsWith("MySearchString")); 
    else 
    result = result.Where(x => x.GetType().GetProperty(i).GetValue(x,null).ToString().ToLower().StartsWith(i.Suchfeld.ToLower(“mySearchString”))); 
} 

私は反射部分を追加する前にかなり速く動作します。すぐに私はそれにリフレクションを追加しましたが、それは1000倍の速度で減速しました。どのように私がそれを得るかどのようなアイデアは、反射部分の周りをスピードアップした。

+0

あなたは "_Before_私は反射部を追加しました" と言うことを意味しましたか? – JLRishe

+0

一部が遅いですか? –

+0

式はLINQ to SQLコンバーターによって複雑に解釈されるため、テーブルのすべての項目でコンパイルおよび実行されます。検索したいプロパティに基づいて式ツリーを構築し、それを 'Expression >'として渡します。 –

答えて

1

式が複雑すぎてLINQ to SQLコンバータによって解釈されないため、テーブルのすべての項目でコンパイルおよび実行されているため、実行が非常に遅いというのは驚くことではありません。

検索するプロパティに基づいて式ツリーを作成し、Expression<Func<MyType, bool>>を作成してWhere(...)メソッドに渡す必要があります。これにより、LINQ to SQLコンバータはそれを認識します。

これを試してみてください:

ParameterExpression param = Expression.Parameter(typeof(MyType)); 
MethodInfo stringStartsWith = typeof(string).GetMethods().First(m => m.Name == "StartsWith" && m.GetParameters().Length == 1); 

PropertyInfo firstProp = typeof(MyType).GetProperty(vm.SearchProperties.First()); 
MemberExpression firstMembAccess = Expression.Property(param, firstProp); 
MethodCallExpression firstStartsWithExpr = Expression.Call(firstMembAccess, stringStartsWith, Expression.Constant(mySearchString)); 
Expression current = firstStartsWithExpr; 

foreach (string s in vm.SearchProperties.Skip(1)) 
{ 
    PropertyInfo prop = typeof(MyType).GetProperty(s); 
    MemberExpression membAccess = Expression.Property(param, prop); 
    MethodCallExpression startsWithExpr = Expression.Call(membAccess, stringStartsWith, Expression.Constant(mySearchString)); 
    current = Expression.OrElse(current, startsWithExpr); 
} 

Expression<Func<MyType, bool>> mySearchExpression = Expression.Lambda<Func<MyType, bool>>(current, param); 

result = db.MyTable.Where(mySearchExpression); 

注:MyTypeはあなたのエンティティタイプが何であれを指します。

0

すでに回答があったので、IQueryableではリフレクションを使用できません。

データがメモリにロードされ、Where句が実行されます。

は、あなたが(where句の前に追加ToListメソッド())以下のコードを行っているかのように似ています:

foreach (var i in vm.SearchProperties) 
{ 
    if (result == null) 
    result = db.MyTable.ToList().Where(x => x.GetType().GetProperty(i).GetValue(x, null).ToString().ToLower().StartsWith("MySearchString")); 
    else 
    result = result.ToList().Where(x => x.GetType().GetProperty(i).GetValue(x,null).ToString().ToLower().StartsWith(i.Suchfeld.ToLower(“mySearchString”))); 
} 

@Mrアンダーソンは権利です。リフレクションの代わりにエクスプレッションツリーを使用する必要があります。

ただし、表現ツリーを使用することは、時には構築するのが非常に複雑になることがあります。

免責事項:私はプロジェクトの所有者だEval-Expression.NET

このプロジェクトでは、実行時に動的な式を評価し、実行することができます。

つまり、動的文字列をwhere句に渡すことができます。

ウィキ:Eval-Expression.NET - LINQ Dynamic

foreach (var i in vm.SearchProperties) 
{ 
    if (result == null) 
    result = db.MyTable.Where(x => "x." + i + ".ToLower().StartsWith('MySearchString')"); 
    else 
    result = result.Where(x => "x." + i + ".ToLower().StartsWith('MySearchString')"); 
}