これは、少なくとも入力を有効なSQL式に変換する実装です。より多くの式タイプを自分で実装する必要がありますが、それがどのように機能するかを理解できます。
この答えはたまたま風塚の答えと非常に似ていますが、式ツリーにExpression.NodeType
演算子がないため、演算子を見つけるために使用されます。MethodInfos
また、これにより実際に必要な数よりも多くの括弧が生成されることに注意してください。括弧の数を減らすには、SQLでの演算子の優先順位を考慮して、式をさらに分析する必要があります。
public static string GetSqlExpression(Expression expression)
{
if (expression is BinaryExpression)
{
return string.Format("({0} {1} {2})",
GetSqlExpression(((BinaryExpression)expression).Left),
GetBinaryOperator((BinaryExpression)expression),
GetSqlExpression(((BinaryExpression)expression).Right));
}
if (expression is MemberExpression)
{
MemberExpression member = (MemberExpression)expression;
// it is somewhat naive to make a bool member into "Member = TRUE"
// since the expression "Member == true" will turn into "(Member = TRUE) = TRUE"
if (member.Type == typeof(bool))
{
return string.Format("([{0}] = TRUE)", member.Member.Name);
}
return string.Format("[{0}]", member.Member.Name);
}
if (expression is ConstantExpression)
{
ConstantExpression constant = (ConstantExpression)expression;
// create a proper SQL representation for each type
if (constant.Type == typeof(int) ||
constant.Type == typeof(string))
{
return constant.Value.ToString();
}
if (constant.Type == typeof(bool))
{
return (bool)constant.Value ? "TRUE" : "FALSE";
}
throw new ArgumentException();
}
throw new ArgumentException();
}
public static string GetBinaryOperator(BinaryExpression expression)
{
switch (expression.NodeType)
{
case ExpressionType.Equal:
return "=";
case ExpressionType.NotEqual:
return "<>";
case ExpressionType.OrElse:
return "OR";
case ExpressionType.AndAlso:
return "AND";
case ExpressionType.LessThan:
return "<";
case ExpressionType.GreaterThan:
return ">";
default:
throw new ArgumentException();
}
}
結果は次のとおりです。
(((([Scale] < 5) OR ([Scale] > 20)) AND ([Scale] <> -100)) OR ([IsExempt] = TRUE))
次のようなメソッドを呼び出します。
string sqlExpression = GetSqlExpression(exprTree.Body);
より機能的な方法で式ツリーを構築することをお勧めします。Func<bool>
コンクリートを使用して構築する代わりに、を使用foo
する必要がありますFunc<Foo, bool>
。ただし、とにかく動作します。正しく見えません。
Expression<Func<Foo, bool>> exprTree =
(foo) => ((foo.Scale < 5 || foo.Scale > 20) && foo.Scale != -100) || foo.IsExempt == true;
明らかに、LINQ to Entitiesを使用できる場合は、通常、SQLテキストを自分で作成する必要はありません。LINQtoエンティティと式ツリーの両方に.NET3.5が必要であり、実際にLINQtosqlステートメントを変換できます。
のような式がSQLServerで機能するかどうかはわかりませんIsExempt = TRUE
。IsExempt = 1
データ型がであるため、そうあるべきだと思いますbit
。また、SQL式ではまたはを使用できないため、またはのような式は個別に処理する必要がありValue == null
ます。またはでなければなりません。Value != null
Value = NULL
Value <> NULL
Value IS NULL
Value IS NOT NULL