这是一个至少可以将您的输入转换为有效 SQL 表达式的实现。您需要自己实现更多表达式类型,但它可以让您了解它是如何工作的。
这个答案恰好与 Kazetsukai 的答案非常相似,但它用于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>
而不是使用混凝土来构建 a ,而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 文本。LINQ to 实体和表达式树都需要 .NET 3.5,您实际上可以将 LINQ 转换为 sql 语句。
我不确定类似的表达式IsExempt = TRUE
是否适用于 SQL Server。我认为应该是IsExempt = 1
因为数据类型是bit
. 由于您不能在 SQL 表达式中使用or ,因此类似Value == null
or的表达式也Value != null
需要单独处理。它必须是或。Value = NULL
Value <> NULL
Value IS NULL
Value IS NOT NULL