C# 使用EFCore时,尝试在Where()子句中使用表达式树时出错

C# 使用EFCore时,尝试在Where()子句中使用表达式树时出错,c#,entity-framework,linq,expression,C#,Entity Framework,Linq,Expression,尝试通过组合其他表达式来编写表达式时出错。目的是在EFCore查询的where()子句中使用它。例如: // Only get users that have been forwarded the request... var request = GetSomeRequestToFilterOn(); var filter = HasRequestBeenForwaredToUserExpression().ReplaceParameter(request); var results = _co

尝试通过组合其他表达式来编写
表达式时出错。目的是在EFCore查询的where()子句中使用它。例如:

// Only get users that have been forwarded the request...
var request = GetSomeRequestToFilterOn();
var filter = HasRequestBeenForwaredToUserExpression().ReplaceParameter(request);
var results = _context.ApplicationUsers.Where(filter).ToList();
在上面的示例中,我通过将表达式中的TransferRequest参数替换为提供的参数,将
表达式
转换为和
表达式
。这在我的单元测试中效果很好,但EFCore似乎不喜欢它,在实际数据库上运行时,我会遇到以下错误:

System.InvalidOperationException:将子表达式从类型
System.Nullable
重写为类型
System.Collections.Generic.IEnumerable
不允许,因为这将更改操作的含义。 如果这是有意的,请覆盖“Visiturary”并将其更改为允许 这是重写。在 System.Linq.Expressions.ExpressionVisitor.ValidateChildType(类型 before,Type after,String methodName)位于 System.Linq.Expressions.ExpressionVisitor.ValidateUnary(UnaryExpression 在…之前,在…之后) System.Linq.Expressions.ExpressionVisitor.Visiturary(UnaryExpression 节点)在 System.Linq.Expressions.UnaryExpression.Accept(ExpressionVisitor 访问者)在System.Linq.Expressions.ExpressionVisitor.visitor(表达式 节点)位于

基本上,如果在最后一个“等待批准”事件之后有任何“转发”事件,即当有新的“等待批准”事件时,先前的“转发”事件不再计算(但仍然存在),则认为某人已“转发”转移请求

这是我的过滤器

internal static Expression<Func<ApplicationUser, TransferRequest, bool>> HasRequestBeenForwaredToUserExpression()
{
    //only "Forwarded" events after the last "Awaiting Approval" event count.
    //so we need to get the last "Awaiting Approval" event from the request.
    var projection = LastAwaitingApprovalEvent();

    var userParam = Expression.Parameter(typeof(ApplicationUser));
    var requestParam = Expression.Parameter(typeof(TransferRequest));
    var requestToEvent = projection.Body.ReplaceParameter(projection.Parameters[0], requestParam);

    Expression<Func<ApplicationUser, TransferRequest, TransferRequestEvent, bool>> condition =
       (user, rqst, evt) => evt != null && rqst.TransferRequestEvents
            .Any(e2 =>
                Equals(e2.EventType, EventType.Forwarded) &&
                Equals(e2.User, user) &&
                e2.EventDateTime > evt.EventDateTime);

    var body = condition.Body
            .ReplaceParameter(condition.Parameters[0], userParam)
            .ReplaceParameter(condition.Parameters[1], requestParam)
            .ReplaceParameter(condition.Parameters[2], requestToEvent);
    return Expression.Lambda<Func<ApplicationUser, TransferRequest, bool>>(body, userParam, requestParam);
}
内部静态表达式hasRequestBeenForwardToUserExpression()
{
//仅在最后一次“等待批准”事件计数后“转发”事件。
//因此,我们需要从请求中获取最后一个“等待批准”事件。
var projection=lastWaitingApprovalEvent();
var userParam=Expression.Parameter(typeof(ApplicationUser));
var requestParam=Expression.Parameter(typeof(TransferRequest));
var requestToEvent=projection.Body.ReplaceParameter(projection.Parameters[0],requestParam);
表达条件=
(用户,rqst,evt)=>evt!=null&&rqst.TransferRequestEvents
.任何(e2=>
等于(e2.EventType,EventType.Forwarded)&&
等于(e2.User,User)&&
e2.EventDateTime>evt.EventDateTime);
var body=条件。body
.ReplaceParameter(条件.Parameters[0],userParam)
.ReplaceParameter(条件参数[1],requestParam)
.ReplaceParameter(条件参数[2],requestToEvent);
返回表达式.Lambda(body、userParam、requestParam);
}
此方法获取最后一个“等待批准”事件

内部静态表达式lastWaitingApprovalEvent()
{
返回t=>t.TransferRequestEvents
.OrderBy(e=>e.EventDateTime).ThenBy(e=>e.Id)
.LastOrDefault(e=>Equals(e.EventType,EventType.WaitingReview));
}
我有一个ExpressionUtility类,用于替换参数:

public class ExpressionUtility
{
    public static Expression ReplaceParameter(this Expression expression,
        ParameterExpression toReplace,
        Expression newExpression)
    {
        return new ParameterReplaceVisitor(toReplace, newExpression)
            .Visit(expression);
    }

    public static Expression<Func<TArg2, TReturn>> ReplaceParameter<TArg1, TArg2, TReturn>(this Expression<Func<TArg1, TArg2, TReturn>> source, TArg1 arg1)
    {
        var t1Param = Expression.Constant(arg1);
        var t2Param = Expression.Parameter(typeof(TArg2));
        var body = source.Body
                    .ReplaceParameter(source.Parameters[0], t1Param)
                    .ReplaceParameter(source.Parameters[1], t2Param);
        return Expression.Lambda<Func<TArg2, TReturn>>(body, t2Param);
    }

    public static Expression<Func<TArg1, TReturn>> ReplaceParameter<TArg1, TArg2, TReturn>(this Expression<Func<TArg1, TArg2, TReturn>> source, TArg2 arg2)
    {
        var t1Param = Expression.Parameter(typeof(TArg1));
        var t2Param = Expression.Constant(arg2);
        var body = source.Body
                    .ReplaceParameter(source.Parameters[0], t1Param)
                    .ReplaceParameter(source.Parameters[1], t2Param);
        return Expression.Lambda<Func<TArg1, TReturn>>(body, t1Param);
    }
}

public class ParameterReplaceVisitor : ExpressionVisitor
{
    private ParameterExpression from;
    private Expression to;
    public ParameterReplaceVisitor(ParameterExpression from, Expression to)
    {
        this.from = from;
        this.to = to;
    }
    protected override Expression VisitParameter(ParameterExpression node)
    {
        return node == from ? to : base.VisitParameter(node);
    }
}
公共类ExpressionUtility
{
公共静态表达式替换参数(此表达式,
参数表达式替换,
表达式(新表达式)
{
返回新参数replaceVisitor(存储替换、新表达式)
.参观(表达);
}
公共静态表达式替换参数(此表达式源,TArg1 arg1)
{
var t1Param=表达式常数(arg1);
var t2Param=表达式参数(typeof(TArg2));
var body=source.body
.ReplaceParameter(源.Parameters[0],t1Param)
.ReplaceParameter(源.Parameters[1],t2Param);
返回表达式.Lambda(body,t2Param);
}
公共静态表达式替换参数(此表达式源,TArg2 arg2)
{
var t1Param=表达式参数(typeof(TArg1));
var t2Param=表达式常数(arg2);
var body=source.body
.ReplaceParameter(源.Parameters[0],t1Param)
.ReplaceParameter(源.Parameters[1],t2Param);
返回表达式.Lambda(body,t1Param);
}
}
公共类参数replaceVisitor:ExpressionVisitor
{
来自的私有参数表达式;
私人表达;
公共参数ReplaceVisitor(参数表达式从,表达式到)
{
this.from=from;
这个;
}
受保护的重写表达式VisitParameter(ParameterExpression节点)
{
返回节点==从?到:base.VisitParameter(节点);
}
}
编辑 当我将最终表达式的ToString打印到控制台时。我明白了

{Param_0=> ((值(debug.Models.TransferRequest.TransferRequestEvents.OrderBy)(e) =>e.EventDateTime)。然后按(e=>e.Id)。LastOrDefault(e=>Equals(e.EventType,EventType.WaitingReview))!=null)和 值(debug.Models.TransferRequest).TransferRequestEvents.Any(e2 =>((等于(e2.EventType,EventType.Forwarded)和(e2.User,Param_0))和(e2.EventDateTime> 值(debug.Models.TransferRequest).TransferRequestEvents.OrderBy(e =>e.EventDateTime)。然后按(e=>e.Id)。LastOrDefault(e=>Equals(e.EventType,EventType.WaitingReview)).EventDateTime))}

另外,下面的代码也可以正常工作

Expression<Func<string, ApplicationUser, bool>> filter = (s, u) => u.FirstName.Contains(s);
var whereClause= filter.ReplaceParameter("mark");
_context.AppicationUsers.Where(whereClause).ToList();
expressionfilter=(s,u)=>u.FirstName.Contains;
var whereClause=filter.ReplaceParameter(“标记”);
_context.applicationUsers.Where(Where子句).ToList();
Expression<Func<string, ApplicationUser, bool>> filter = (s, u) => u.FirstName.Contains(s);
var whereClause= filter.ReplaceParameter("mark");
_context.AppicationUsers.Where(whereClause).ToList();