LINQ Expression Problem
I have a Linq Expression that is giving me a real headache and hope someone can help me find out why my provider does not like it.
If I do the following it works fine;
Expression<Func<Employee, bool>> expr = e => e.Participant == "Y";
_context.Employees.Where(expr).ToList<IEmployee>();
However, if I do the following my provider doesn't like it.
Expression<Func<IEmployee, bool>> expr = e => e.Participant == "Y";
Expression<Func<Employee, bool>> convertedExpr = ParameterReplacer.Replace
<Func<IEmployee, bool>, Func<Employee, bool>>
(expr,
expr.Parameters.Single(),
Expression.Parameter(typeof(Employee)));
_context.Employees.Where(convertedExpr).ToList<IEmployee>();
The reason I am doing the conversion is that the upper layer of my application only knows about the interface type, so I convert it to a Expression that uses the concrete type in the lower layer using the ParameterReplacer
(kindly supplied by another SO member).
I have compared the linq expressions between the version that works and the one that doesn't and the only difference I can see is in what I see in the DebugView property in that the parameter names are different.
Here is the code for the ParameterReplacer
;
public static class ParameterReplacer
{
// Produces an expression identical to 'expression'
// except with 'source' parameter replaced with 'target' parameter.
public static Expression<TOutput> Replace<TInput, TOutput>(Expression<TInput> expression, ParameterExpression source, ParameterExpression target)
{
return new ParameterReplacerVisitor<TOutput>(source, target).VisitAndConvert(expression);
}
private class ParameterReplacerVisitor<TOutput> : ExpressionVisitor
{
private ParameterExpression _source;
private ParameterExpression _target;
public ParameterReplacerVisitor(ParameterExpression source, ParameterExpression target)
{
_source = source;
_target = target;
}
internal Expression<TOutput> VisitAndConvert<T>(Expression<T> root)
{
return (Expression<TOutput>)VisitLambda(root);
}
protected override Expression VisitLambda<T>(Expression<T> node)
{
// Leave all parameters alone except the one we want to replace.
var parameters = node.Parameters.Select(p => p == _source ? _target : p);
return Expression.Lambda<TOutput>(Visit(node.Body), parameters);
}
protected override Expression VisitParameter(ParameterExpression node)
{
// Replace the source with the target, visit other params as usual.
return node == _source ? _target : base.VisitParameter(node);
}
}
}
Is this an issue with the ParameterReplacer or my provider? Can any one help me out?
The provider I am using is Telerik OpenAccess and the exception its throwing is;
InnerException: System.NullReferenceException Message=Object reference not set to an instance of an object. Source=Telerik.OpenAccess.35.Extensions StackTrace: at Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQueryImpl(Type type, Int32 elementAt, O开发者_StackOverflow社区bject[] groupResolutionParamValues, Boolean single, Boolean checkOid) at Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQuery(Type type, Int32 elementAt, Object[] groupResolutionParamValues, Boolean single, Boolean checkOid) InnerException:
I have never used your provider, so I can't be sure, but considering the circumstances, I think this is good bet:
Since, the only difference is that the parameter in the second expression has null Name
and the exception you are getting is a null reference exception, I think that's exactly the problem. Try changing the Name
to something non-null.
That means changing the creation of the new parameter to something like:
Expression.Parameter(typeof(Employee), "e")
精彩评论