我有一种情况需要将linq查询中的局部变量引用转换为其值。 为此,我使用此类在查询中执行转换局部变量引用:
public static class Evaluator
{
public static Expression PartialEval(Expression expression, Func<Expression, bool> fnCanBeEvaluated)
{
return new SubtreeEvaluator(new Nominator(fnCanBeEvaluated).Nominate(expression)).Eval(expression);
}
public static Expression PartialEval(Expression expression)
{
return PartialEval(expression, Evaluator.CanBeEvaluatedLocally);
}
private static bool CanBeEvaluatedLocally(Expression expression)
{
return expression.NodeType != ExpressionType.Parameter;
}
class SubtreeEvaluator: ExpressionVisitor
{
HashSet<Expression> candidates;
internal SubtreeEvaluator(HashSet<Expression> candidates)
{
this.candidates = candidates;
}
internal Expression Eval(Expression exp)
{
return this.Visit(exp);
}
protected override Expression Visit(Expression exp)
{
if (exp == null)
{
return null;
}
if (this.candidates.Contains(exp))
{
return this.Evaluate(exp);
}
return base.Visit(exp);
}
private Expression Evaluate(Expression e)
{
if (e.NodeType == ExpressionType.Constant)
{
return e;
}
LambdaExpression lambda = Expression.Lambda(e);
Delegate fn = lambda.Compile();
return Expression.Constant(fn.DynamicInvoke(null), e.Type);
}
}
class Nominator : ExpressionVisitor
{
Func<Expression, bool> fnCanBeEvaluated;
HashSet<Expression> candidates;
bool cannotBeEvaluated;
internal Nominator(Func<Expression, bool> fnCanBeEvaluated)
{
this.fnCanBeEvaluated = fnCanBeEvaluated;
}
internal HashSet<Expression> Nominate(Expression expression)
{
this.candidates = new HashSet<Expression>();
this.Visit(expression);
return this.candidates;
}
protected override Expression Visit(Expression expression)
{
if (expression != null)
{
bool saveCannotBeEvaluated = this.cannotBeEvaluated;
this.cannotBeEvaluated = false;
base.Visit(expression);
if (!this.cannotBeEvaluated)
{
if (this.fnCanBeEvaluated(expression))
{
this.candidates.Add(expression);
}
else
{
this.cannotBeEvaluated = true;
}
}
this.cannotBeEvaluated |= saveCannotBeEvaluated;
}
return expression;
}
}
}
在翻译局部变量引用之后,使用如下:
public class DbQueryProvider : QueryProvider
{
// …
private string Translate(Expression expression)
{
expression = Evaluator.PartialEval(expression);
return new QueryTranslator().Translate(expression);
}
}
例如,如果我有这个表达式:
string ct = "London";
var query = db.Customers.Where(c => c.City == ct);
翻译后返回的表达式为:
SELECT * FROM (SELECT * FROM Customers) AS T WHERE (City = 'London')
代码工作正常,包含所有类型的变量,DateTime除外。 在我的数据库中,我只保存日期部分(没有时间),例如02/03/2012。
现在,如果我有这个问题:
DateTime dt1 = Convert.ToDateTime("01/01/2012");
var query = db.Orders.Where(c => c.dt == dt1);
如果我尝试翻译,则返回的表达式为:
SELECT * FROM (SELECT * FROM Orders) AS T WHERE (dt = '01/01/2012 12:00:00 AM')
正如您所看到的,翻译后的查询包含最后的时间,而我的查询每次都不会返回任何记录。
我该怎么办?
答案 0 :(得分:-2)
var query = db.Orders.Where(c => c.dt == dt1.ToString("MM/dd/yyyy"));