在this post标记的答案之后,我将
Evaluator.cs
复制到我的项目中进行部分评估,以便能够解析表达式的局部变量。不管怎样,我似乎遗漏了一些东西,因为对我来说它并没有简化表达式,并且常量被保留为原始表达式作为编译器生成的匿名类的实例:
我的访问者的 VisitMember 方法如下所示:
protected override Expression VisitMember(MemberExpression m)
{
if (m.Expression != null && m.Expression.NodeType == ExpressionType.Parameter)
{
sqlBuilder.AddColumn(m.Member.GetFieldName());
return m;
}
else if (m.Expression != null && m.Expression.NodeType == ExpressionType.Constant)
{
var partialEval = Evaluator.PartialEval(m.Expression);
this.Visit(partialEval);
return m;
}
throw new NotSupportedException(string.Format("The member '{0}' is not supported", m.Member.Name));
}
更新:为了更好地理解我想要做什么,这是我正在执行的单元测试,以测试输出 sql 是否正确:
[Theory]
[InlineData("Test1")]
[InlineData("Test2")]
[InlineData("Test3")]
public void SelectWhereExpression_NameEquals(string name)
{
using var sqlbuilder = GetSpecificBuilder();
string sql = sqlbuilder.Select()
.Where(obj => obj.Name == name)
.Build().SqlCommand;
var selectSql = SelectAllRecordsExpectedSql.Remove(SelectAllRecordsExpectedSql.Length - 1, 1);
Assert.Equal($"{selectSql} WHERE (Name = '{name}')", sql);
}
.Where() 方法将表达式作为参数,并使用该表达式调用我的 SqlVisitor:
public virtual SqlBuilder<T> Where(Expression<Func<T, bool>> expression)
{
BuiltObject.Append(" WHERE");
ExpressionToSQLVisitor<T> expressionToSQL = new(this);
expressionToSQL.Visit(expression);
return this;
}
我做错了什么?
会稍微改变你的代码。您打算如何呈现值取决于您。 主要变化是覆盖
VisitConstant
中的 ExpressionToSQLVisitor
。
protected override Expression VisitMember(MemberExpression node)
{
if (node.Expression?.NodeType == ExpressionType.Parameter)
{
sqlBuilder.AddColumn(node.Member.GetFieldName());
return node;
}
else
{
var partialEval = Evaluator.PartialEval(node);
if (!ReferenceEquals(partialEval, node))
return Visit(partialEval);
}
throw new NotSupportedException(string.Format("The member '{0}' is not supported", node.Member.Name));
}
protected override Expression VisitConstant(ConstantExpression node)
{
sqlBuilder.AddValue(node.Value);
return node;
}