/// <summary> /// Resolves types for the specified expression. /// </summary> /// <param name="expression">The expression to resolve types for.</param> /// <returns>Expression with resolved types.</returns> public QueryExpression Visit(QueryConstantExpression expression) { if (expression.ExpressionType.IsUnresolved) { var value = expression.ScalarValue.Value; ExceptionUtilities.Assert(value != null, "Constant expression with unresolved type cannot have null value."); var queryType = this.GetQueryScalarTypeFromObjectValue(value); return(CommonQueryBuilder.Constant(queryType.CreateValue(value))); } return(expression); }
/// <summary> /// Evaluates the specified expression. /// </summary> /// <param name="expression">The expression to evaluate.</param> /// <returns>Value of the expression.</returns> public virtual QueryValue Visit(QueryCustomFunctionCallExpression expression) { QueryValue result; var argumentValues = this.EvaluateArguments(expression.Arguments); var customEvaluator = expression.Function.Annotations.OfType <FunctionEvaluatorAnnotation>().Select(a => a.FunctionEvaluator).SingleOrDefault(); if (customEvaluator != null) { result = customEvaluator(expression.ExpressionType, argumentValues); } else if (expression.FunctionBody != null) { QueryExpression functionBody = expression.FunctionBody; // replace parameter refs with arguments if (expression.Function.Parameters.Any()) { // Consider query: // "select value DefaultNamespace.GetCustomer(c.CustomerId) from [DefaultContainer].[Customer] as c" where GetCustomer is a function. // After we replace parameter references in the function's body with "c.CustomerId" expression evaluation // of the body expression fails becuase variable "c" is not in the scope for the function's body. // Note also that function body itself can have a variable reference with the same name "c". // So the right thing is to evaluate each argument and then replace parameter references with constant expressions. // However QueryConstantExpression currently only supports QueryScalarType/QueryScalarValue. // So for now we only evaluating scalar arguments. // TODO: add supoort for non-scalar constants and change the following code to evaluate each argument // NOTE: we have similar limitation in LinqToEntitiesEvaluator List <QueryExpression> evaluatedArguments = new List <QueryExpression>(); foreach (var argument in expression.Arguments) { QueryScalarType scalarArgumentType = argument.ExpressionType as QueryScalarType; if (scalarArgumentType != null) { QueryScalarValue scalarValue = (QueryScalarValue)this.Evaluate(argument); var constant = CommonQueryBuilder.Constant(scalarValue); evaluatedArguments.Add(constant); } else { evaluatedArguments.Add(argument); } } var visitor = this.CreateFunctionParameterReferenceReplacingVisitor(expression.Function, evaluatedArguments); functionBody = visitor.ReplaceExpression(expression.FunctionBody); } result = this.Evaluate(functionBody); } else { result = expression.ExpressionType.EvaluationStrategy.EvaluateFunction( expression.ExpressionType, expression.Function, argumentValues); } return(result); }