我有一个Linq表达式给我带来了真正的头痛,并希望有人可以帮助我找出我的提供商不喜欢它的原因。
如果我执行以下操作,它可以正常工作;
Expression<Func<Employee, bool>> expr = e => e.Participant == "Y";
_context.Employees.Where(expr).ToList<IEmployee>();
但是,如果我执行以下操作,我的提供商不喜欢它。
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>();
我进行转换的原因是我的应用程序的上层只知道接口类型,因此我将其转换为使用ParameterReplacer
在下层使用具体类型的Expression(由另一个SO成员提供)。
我已经比较了有效版本和不可用版本之间的linq表达式,我可以看到的唯一区别是我在DebugView属性中看到的参数名称不同。
以下是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);
}
}
}
这是ParameterReplacer或我的提供商的问题吗?任何人都可以帮助我吗?
我使用的提供程序是Telerik OpenAccess,它的抛出是异常;
InnerException:System.NullReferenceException Message =对象引用未设置为对象的实例。 来源= Telerik.OpenAccess.35.Extensions 堆栈跟踪: 在 Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQueryImpl(类型 type,Int32 elementAt,Object [] groupResolutionParamValues,Boolean single,Boolean checkOid) 在 Telerik.OpenAccess.Query.ExpressionCompiler.PerformDatabaseQuery(类型 type,Int32 elementAt,Object [] groupResolutionParamValues,Boolean single,Boolean checkOid) 的InnerException:
答案 0 :(得分:1)
我从未使用过您的提供商,所以我无法确定,但考虑到情况,我认为这是个不错的选择:
因为,唯一的区别是第二个表达式中的参数为null Name
,并且您获得的异常是一个空引用异常,我认为这正是问题所在。尝试将Name
更改为非空值。
这意味着将新参数的创建更改为:
Expression.Parameter(typeof(Employee), "e")