私は、毎日実行される自動化されたジョブに関する情報(ジョブの名前、実行時間、結果など)をログに記録する、システムの一部のデータレイヤーを作成中です。
Entity Frameworkを使用してデータベースと通信していますが、これらの詳細を上位レベルのモジュールから隠そうとしているため、エンティティオブジェクト自体を公開したくありません。
ただし、仕事の情報を検索するために使用する基準で、インターフェイスを非常に柔軟にしたいと思います。たとえば、ユーザーインターフェースでは、ユーザーが「午前10時から午前11時の間に実行された「hello」という名前のすべてのジョブが失敗した」などの複雑なクエリを実行できるようにする必要があります。Expression
明らかに、これは動的に構築されたツリーの仕事のように見えます。
したがって、データレイヤー(リポジトリ)で実行できるようにするのは、型のLINQ式Expression<Func<string, DateTime, ResultCode, long, bool>>
(ラムダ式)を受け入れ、そのラムダを、EntityFrameworkが句ObjectContext
内のフィルターとして使用できる式に変換することです。 Where()
。
一言で言えば、私はタイプのラムダ式をに変換しようとしExpression<Func<string, DateTime, ResultCode, long, bool>>
ています。Expression<Func<svc_JobAudit, bool>>
ここsvc_JobAudit
で、はジョブ情報が格納されているテーブルに対応するEntityFrameworkデータオブジェクトです。(最初のデリゲートの4つのパラメーターは、ジョブの名前、実行時、結果、およびMSでの所要時間にそれぞれ対応します)
ExpressionVisitor
レンガの壁にぶつかってInvalidOperationException
次のエラーメッセージが表示されるまで、クラスの使用は非常に順調に進んでいました。
'VisitLambda'から呼び出された場合、タイプ'System.Linq.Expressions.ParameterExpression'のノードを書き換えると、同じタイプのnull以外の値が返される必要があります。または、「VisitLambda」をオーバーライドして、このタイプの子を訪問しないように変更します。
私は完全に困惑しています。パラメータを参照する式ノードをプロパティを参照するノードに変換できないのはなぜですか?これについて別の方法はありますか?
サンプルコードは次のとおりです。
namespace ExpressionTest
{
class Program
{
static void Main(string[] args)
{
Expression<Func<string, DateTime, ResultCode, long, bool>> expression = (myString, myDateTime, myResultCode, myTimeSpan) => myResultCode == ResultCode.Failed && myString == "hello";
var result = ConvertExpression(expression);
}
private static Expression<Func<svc_JobAudit, bool>> ConvertExpression(Expression<Func<string, DateTime, ResultCode, long, bool>> expression)
{
var newExpression = Expression.Lambda<Func<svc_JobAudit, bool>>(new ReplaceVisitor().Modify(expression), Expression.Parameter(typeof(svc_JobAudit)));
return newExpression;
}
}
class ReplaceVisitor : ExpressionVisitor
{
public Expression Modify(Expression expression)
{
return Visit(expression);
}
protected override Expression VisitParameter(ParameterExpression node)
{
if (node.Type == typeof(string))
{
return Expression.Property(Expression.Parameter(typeof(svc_JobAudit)), "JobName");
}
return node;
}
}
}