public override Expression VisitExpression(Expression expression) { // Only evaluate expressions which do not use any of the surrounding parameter expressions. Don't evaluate // lambda expressions (even if you could), we want to analyze those later on. if (expression == null) { return(null); } if (expression.NodeType == ExpressionType.Lambda || !_partialEvaluationInfo.IsEvaluatableExpression(expression)) { return(base.VisitExpression(expression)); } Expression evaluatedExpression; try { evaluatedExpression = EvaluateSubtree(expression); } catch (Exception ex) { // Evaluation caused an exception. Skip evaluation of this expression and proceed as if it weren't evaluable. var baseVisitedExpression = base.VisitExpression(expression); // Then wrap the result to capture the exception for the back-end. return(new PartialEvaluationExceptionExpression(ex, baseVisitedExpression)); } if (evaluatedExpression != expression) { return(EvaluateIndependentSubtrees(evaluatedExpression)); } return(evaluatedExpression); }
public override Expression Visit(Expression expression) { if (expression == null) { return(null); } if (expression.NodeType != ExpressionType.Lambda) { if (_partialEvaluationInfo.IsEvaluatableExpression(expression)) { Expression subtree; try { subtree = EvaluateSubtree(expression); } catch (Exception ex) { return(new PartialEvaluationExceptionExpression(ex, base.Visit(expression))); } if (subtree != expression) { return(EvaluateIndependentSubtrees(subtree)); } return(subtree); } } return(base.Visit(expression)); }
public override Expression VisitExpression(Expression expression) { // Only evaluate expressions which do not use any of the surrounding parameter expressions. Don't evaluate // lambda expressions (even if you could), we want to analyze those later on. if (expression == null) { return(null); } else if (expression.NodeType != ExpressionType.Lambda && _partialEvaluationInfo.IsEvaluatableExpression(expression)) { var evaluatedExpression = EvaluateSubtree(expression); if (evaluatedExpression != expression) { return(EvaluateIndependentSubtrees(evaluatedExpression)); } else { return(evaluatedExpression); } } else { return(base.VisitExpression(expression)); } }
protected override Expression VisitMember(MemberExpression memberExpression) { if (!_partialEvaluationInfo.IsEvaluatableExpression(memberExpression)) { return(base.VisitMember(memberExpression)); } if (!_queryableTypeInfo.IsAssignableFrom(memberExpression.Type.GetTypeInfo())) { return(TryExtractParameter(memberExpression)); } string _; var queryable = (IQueryable)Evaluate(memberExpression, out _); return(ExtractParameters(queryable.Expression)); }
public override Expression Visit(Expression expression) { // Only evaluate expressions which do not use any of the surrounding parameter expressions. Don't evaluate // lambda expressions (even if you could), we want to analyze those later on. if (expression == null) { return(null); } if (expression.NodeType == ExpressionType.Lambda || !_partialEvaluationInfo.IsEvaluatableExpression(expression) || #region NH additions // Variables should be evaluated only when they are part of an evaluatable expression (e.g. o => string.Format("...", variable)) expression is UnaryExpression unaryExpression && ExpressionsHelper.IsVariable(unaryExpression.Operand, out _, out _)) #endregion { return(base.Visit(expression)); } Expression evaluatedExpression; try { evaluatedExpression = EvaluateSubtree(expression); } catch (Exception ex) { // Evaluation caused an exception. Skip evaluation of this expression and proceed as if it weren't evaluable. var baseVisitedExpression = base.Visit(expression); throw new HibernateException($"Evaluation failure on {baseVisitedExpression}", ex); } if (evaluatedExpression != expression) { evaluatedExpression = EvaluateIndependentSubtrees(evaluatedExpression, _preTransformationParameters); } #region NH additions // When having multiple level closure, we have to evaluate each closure independently if (evaluatedExpression is ConstantExpression constantExpression) { evaluatedExpression = VisitConstant(constantExpression); } // Variables in expressions are never a constant, they are encapsulated as fields of a compiler generated class. if (expression.NodeType != ExpressionType.Constant && _preTransformationParameters.MinimizeParameters && evaluatedExpression is ConstantExpression variableConstant && !_preTransformationParameters.QueryVariables.ContainsKey(variableConstant) && ExpressionsHelper.IsVariable(expression, out var path, out var closureContext)) { _preTransformationParameters.QueryVariables.Add(variableConstant, new QueryVariable(path, closureContext)); } #endregion return(evaluatedExpression); }
/// <remarks> /// Parameters are evaluatable if they are supplied by evaluatable expression. /// Look up lambda defining the parameter, up the ancestor list and check if method call to which it is passed is on evaluatable /// instance or extension method accepting evaluatable arguments. /// Note that lambda body is visited prior to parameters. /// Since method call is visited in the order [instance, arguments] and extension methods get instance as first parameter /// the source of the parameter is already visited and its evaluatability established. /// </remarks>> private ParameterStatus CalcParameterStatus(ParameterExpression expression) { if (expression == null) { throw new ArgumentNullException(nameof(expression)); } var result = new ParameterStatus { Expression = expression }; foreach (var ancestor in _ancestors) { if (result.MethodArgumentAcceptingLambda == null && IsParameterOwner(ancestor, expression)) { result.MethodArgumentAcceptingLambda = result.OwningExpression = (LambdaExpression)ancestor; } else if (result.MethodArgumentAcceptingLambda != null) { if (ancestor.NodeType == ExpressionType.Call) { result.MethodCallInvokingLambda = (MethodCallExpression)ancestor; result.IsEvaluatable = result.MethodCallInvokingLambda.Object != null ? PartialEvaluationInfo.IsEvaluatableExpression(result.MethodCallInvokingLambda.Object) : result.MethodCallInvokingLambda.Arguments.All(a => a == result.MethodArgumentAcceptingLambda || ( PartialEvaluationInfo.IsEvaluatableExpression(a) // member expressions on e.g. repository creating query instances must be evaluated into constants // but parameters accepting values from them are not evaluatable && !typeof(IQueryable).IsAssignableFrom(a.Type))); return(result); } result.MethodArgumentAcceptingLambda = ancestor; } } return(result); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { var methodInfo = methodCallExpression.Method; var declaringType = methodInfo.DeclaringType; if (declaringType == typeof(Queryable) || declaringType == typeof(EntityFrameworkQueryableExtensions) && (!methodInfo.IsGenericMethod || !methodInfo.GetGenericMethodDefinition() .Equals(EntityFrameworkQueryableExtensions.StringIncludeMethodInfo))) { return(base.VisitMethodCall(methodCallExpression)); } var returnTypeInfo = methodInfo.ReturnType.GetTypeInfo(); if (returnTypeInfo.IsGenericType && returnTypeInfo.GetGenericTypeDefinition() == typeof(DbSet <>)) { var queryable = (IQueryable)Evaluate(methodCallExpression, out _); return(ExtractParameters(queryable.Expression)); } if (_partialEvaluationInfo.IsEvaluatableExpression(methodCallExpression)) { if (_queryableTypeInfo.IsAssignableFrom(methodCallExpression.Type)) { var queryable = (IQueryable)Evaluate(methodCallExpression, out _); return(ExtractParameters(queryable.Expression)); } return(TryExtractParameter(methodCallExpression)); } if (!methodInfo.IsStatic) { return(base.VisitMethodCall(methodCallExpression)); } ParameterInfo[] parameterInfos = null; Expression[] newArguments = null; var arguments = methodCallExpression.Arguments; for (var i = 0; i < arguments.Count; i++) { var argument = arguments[i]; var newArgument = Visit(argument); if (newArgument != argument) { if (newArguments == null) { parameterInfos = methodInfo.GetParameters(); newArguments = new Expression[arguments.Count]; for (var j = 0; j < i; j++) { newArguments[j] = arguments[j]; } } if (parameterInfos[i].GetCustomAttribute <NotParameterizedAttribute>() != null) { if (newArgument.RemoveConvert() is ParameterExpression parameter) { var parameterValue = _parameterValues.RemoveParameter(parameter.Name); if (parameter.Type == typeof(FormattableString)) { if (Evaluate(methodCallExpression, out _) is IQueryable queryable) { var oldInLambda = _inLambda; _inLambda = false; try { return(ExtractParameters(queryable.Expression)); } finally { _inLambda = oldInLambda; } } } else { var constantParameterValue = Expression.Constant(parameterValue); if (newArgument is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert) { newArgument = unaryExpression.Update(constantParameterValue); } else { newArgument = constantParameterValue; } } } } newArguments[i] = newArgument; }
public override Expression Visit(Expression expression) { if (expression == null) { return(null); } if (expression.NodeType == ExpressionType.Lambda || !_partialEvaluationInfo.IsEvaluatableExpression(expression)) { return(base.Visit(expression)); } var e = expression; if (expression.NodeType == ExpressionType.Convert) { if (expression.RemoveConvert() is ConstantExpression) { return(expression); } var unaryExpression = (UnaryExpression)expression; if ((unaryExpression.Type.IsNullableType() && !unaryExpression.Operand.Type.IsNullableType()) || unaryExpression.Type == typeof(object)) { e = unaryExpression.Operand; } } if (!typeof(IQueryable).GetTypeInfo().IsAssignableFrom(e.Type.GetTypeInfo())) { var constantExpression = e as ConstantExpression; if (constantExpression == null || (constantExpression.Type != typeof(string) && constantExpression.Type != typeof(byte[]) && constantExpression.Value is IEnumerable)) { try { string parameterName; var parameterValue = ExpressionEvaluationHelpers.Evaluate(e, out parameterName); if (parameterName == null) { parameterName = "p"; } var compilerPrefixIndex = parameterName.LastIndexOf(">", StringComparison.Ordinal); if (compilerPrefixIndex != -1) { parameterName = parameterName.Substring(compilerPrefixIndex + 1); } parameterName = $"{CompiledQueryCache.CompiledQueryParameterPrefix}{parameterName}_{_queryContext.ParameterValues.Count}"; _queryContext.ParameterValues.Add(parameterName, parameterValue); return(e.Type == expression.Type ? Expression.Parameter(e.Type, parameterName) : (Expression)Expression.Convert( Expression.Parameter(e.Type, parameterName), expression.Type)); } catch (Exception exception) { throw new InvalidOperationException( CoreStrings.ExpressionParameterizationException(expression), exception); } } } return(expression); }
/// <summary> /// This API supports the Entity Framework Core infrastructure and is not intended to be used /// directly from your code. This API may change or be removed in future releases. /// </summary> protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { var methodInfo = methodCallExpression.Method; var declaringType = methodInfo.DeclaringType; if (declaringType == typeof(DbContext)) { return(methodCallExpression); } if (declaringType == typeof(Queryable) || (declaringType == typeof(EntityFrameworkQueryableExtensions) && (!methodInfo.IsGenericMethod || methodInfo.GetGenericMethodDefinition() != EntityFrameworkQueryableExtensions.StringIncludeMethodInfo))) { return(base.VisitMethodCall(methodCallExpression)); } if (_partialEvaluationInfo.IsEvaluatableExpression(methodCallExpression)) { return(TryExtractParameter(methodCallExpression)); } if (!methodInfo.IsStatic) { return(base.VisitMethodCall(methodCallExpression)); } ParameterInfo[] parameterInfos = null; Expression[] newArguments = null; var arguments = methodCallExpression.Arguments; for (var i = 0; i < arguments.Count; i++) { var argument = arguments[i]; var newArgument = Visit(argument); if (newArgument != argument) { if (newArguments == null) { parameterInfos = methodInfo.GetParameters(); newArguments = new Expression[arguments.Count]; for (var j = 0; j < i; j++) { newArguments[j] = arguments[j]; } } if (parameterInfos[i].GetCustomAttribute <NotParameterizedAttribute>() != null) { var parameter = newArgument.RemoveConvert() as ParameterExpression; if (parameter != null) { newArgument = Expression.Constant(_queryContext.RemoveParameter(parameter.Name)); } } newArguments[i] = newArgument; } else if (newArguments != null) { newArguments[i] = newArgument; } } if (newArguments != null) { methodCallExpression = methodCallExpression.Update(methodCallExpression.Object, newArguments); } return(methodCallExpression); }
public override Expression VisitExpression(Expression expression) { if (expression == null) { return(null); } if (expression.NodeType == ExpressionType.Lambda || !_partialEvaluationInfo.IsEvaluatableExpression(expression)) { return(base.VisitExpression(expression)); } var e = expression; if (expression.NodeType == ExpressionType.Convert) { var unaryExpression = (UnaryExpression)expression; if (unaryExpression.Type.IsNullableType() && !unaryExpression.Operand.Type.IsNullableType()) { e = unaryExpression.Operand; } } if (e.NodeType != ExpressionType.Constant && !typeof(IQueryable).GetTypeInfo().IsAssignableFrom(e.Type.GetTypeInfo())) { try { string parameterName; var parameterValue = Evaluate(e, out parameterName); var compilerPrefixIndex = parameterName.LastIndexOf(">"); if (compilerPrefixIndex != -1) { parameterName = parameterName.Substring(compilerPrefixIndex + 1); } parameterName = string.Format("{0}{1}_{2}", CompiledQueryParameterPrefix, parameterName, _queryContext.ParameterValues.Count); _queryContext.ParameterValues.Add(parameterName, parameterValue); return(Expression.Parameter(expression.Type, parameterName)); } catch (Exception exception) { throw new InvalidOperationException( Strings.ExpressionParameterizationException(expression), exception); } } return(expression); }