protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName)) { return(BindProperty(source, propertyName)); } var subqueryTranslation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); if (subqueryTranslation != null) { if (subqueryTranslation.ResultType == ResultType.Enumerable) { return(null); } var subquery = (SelectExpression)subqueryTranslation.QueryExpression; subquery.ApplyProjection(); if (subquery.Projection.Count != 1) { return(null); } if ((methodCallExpression.Method.Name == nameof(Queryable.Any) || methodCallExpression.Method.Name == nameof(Queryable.All) || methodCallExpression.Method.Name == nameof(Queryable.Contains)) && subquery.Tables.Count == 0) { return(subquery.Projection[0].Expression); } return(new SubSelectExpression(subquery)); } var @object = Visit(methodCallExpression.Object); if (TranslationFailed(methodCallExpression.Object, @object)) { return(null); } var arguments = new SqlExpression[methodCallExpression.Arguments.Count]; for (var i = 0; i < arguments.Length; i++) { var argument = Visit(methodCallExpression.Arguments[i]); if (TranslationFailed(methodCallExpression.Arguments[i], argument)) { return(null); } arguments[i] = (SqlExpression)argument; } return(_methodCallTranslatorProvider.Translate(_model, (SqlExpression)@object, methodCallExpression.Method, arguments)); }
protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { // EF.Property case if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName)) { if (TryBindMember(source, MemberIdentity.Create(propertyName), out var result)) { return(result); } #pragma warning disable CA1303 // Do not pass literals as localized parameters throw new InvalidOperationException("EF.Property called with wrong property name."); #pragma warning restore CA1303 // Do not pass literals as localized parameters } // GroupBy Aggregate case if (methodCallExpression.Object == null && methodCallExpression.Method.DeclaringType == typeof(Enumerable) && methodCallExpression.Arguments.Count > 0 && methodCallExpression.Arguments[0] is GroupByShaperExpression groupByShaperExpression) { var translatedAggregate = methodCallExpression.Method.Name switch { nameof(Enumerable.Average) => TranslateAverage(GetSelector(methodCallExpression, groupByShaperExpression)), nameof(Enumerable.Count) => TranslateCount(GetPredicate(methodCallExpression, groupByShaperExpression)), nameof(Enumerable.LongCount) => TranslateLongCount(GetPredicate(methodCallExpression, groupByShaperExpression)), nameof(Enumerable.Max) => TranslateMax(GetSelector(methodCallExpression, groupByShaperExpression)), nameof(Enumerable.Min) => TranslateMin(GetSelector(methodCallExpression, groupByShaperExpression)), nameof(Enumerable.Sum) => TranslateSum(GetSelector(methodCallExpression, groupByShaperExpression)), _ => null }; if (translatedAggregate == null) { throw new InvalidOperationException(CoreStrings.TranslationFailed(methodCallExpression.Print())); } return(translatedAggregate); } // Subquery case var subqueryTranslation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); if (subqueryTranslation != null) {
public override Expression Visit(Expression expression) { if (expression == null) { return(null); } if (!(expression is NewExpression || expression is MemberInitExpression || expression is EntityShaperExpression || expression is IncludeExpression)) { // This skips the group parameter from GroupJoin if (expression is ParameterExpression parameter && parameter.Type.IsGenericType && parameter.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>)) { return(parameter); } if (_clientEval) { switch (expression) { case ConstantExpression _: return(expression); case MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression: //return _selectExpression.AddCollectionProjection( // _queryableMethodTranslatingExpressionVisitor.TranslateSubquery( // materializeCollectionNavigationExpression.Subquery), // materializeCollectionNavigationExpression.Navigation, null); throw new NotImplementedException(); case MethodCallExpression methodCallExpression: { if (methodCallExpression.Method.IsGenericMethod && methodCallExpression.Method.DeclaringType == typeof(Enumerable) && methodCallExpression.Method.Name == nameof(Enumerable.ToList)) { //var elementType = methodCallExpression.Method.GetGenericArguments()[0]; //var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]); //return _selectExpression.AddCollectionProjection(result, null, elementType); throw new NotImplementedException(); } var subquery = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); if (subquery != null) { //if (subquery.ResultType == ResultType.Enumerable) //{ // return _selectExpression.AddCollectionProjection(subquery, null, subquery.ShaperExpression.Type); //} throw new NotImplementedException(); } break; } } var translation = _expressionTranslatingExpressionVisitor.Translate(expression); return(translation == null ? base.Visit(expression) : new ProjectionBindingExpression(_queryExpression, _queryExpression.AddToProjection(translation), expression.Type)); } else { var translation = _expressionTranslatingExpressionVisitor.Translate(expression); if (translation == null) { return(null); } _projectionMapping[_projectionMembers.Peek()] = translation; return(new ProjectionBindingExpression(_queryExpression, _projectionMembers.Peek(), expression.Type)); } } return(base.Visit(expression)); }
public override Expression Visit(Expression expression) { if (expression == null) { return(null); } if (!(expression is NewExpression || expression is MemberInitExpression || expression is EntityShaperExpression || expression is IncludeExpression)) { // This skips the group parameter from GroupJoin if (expression is ParameterExpression parameter && parameter.Type.IsGenericType && parameter.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>)) { return(parameter); } if (_clientEval) { if (expression is ConstantExpression) { return(expression); } if (expression is ParameterExpression parameterExpression) { return(Expression.Call( _getParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type), QueryCompilationContext.QueryContextParameter, Expression.Constant(parameterExpression.Name))); } if (expression is MaterializeCollectionNavigationExpression materializeCollectionNavigationExpression) { return(_selectExpression.AddCollectionProjection( _queryableMethodTranslatingExpressionVisitor.TranslateSubquery( materializeCollectionNavigationExpression.Subquery), materializeCollectionNavigationExpression.Navigation, null)); } if (expression is MethodCallExpression methodCallExpression) { if (methodCallExpression.Method.IsGenericMethod && methodCallExpression.Method.DeclaringType == typeof(Enumerable) && methodCallExpression.Method.Name == nameof(Enumerable.ToList)) { var elementType = methodCallExpression.Method.GetGenericArguments()[0]; var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]); return(_selectExpression.AddCollectionProjection(result, null, elementType)); } var subquery = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); if (subquery != null) { if (subquery.ResultType == ResultType.Enumerable) { return(_selectExpression.AddCollectionProjection(subquery, null, subquery.ShaperExpression.Type)); } } } var translation = _sqlTranslator.Translate(expression); if (translation == null) { return(base.Visit(expression)); } else { return(new ProjectionBindingExpression(_selectExpression, _selectExpression.AddToProjection(translation), expression.Type)); } } else { var translation = _sqlTranslator.Translate(expression); if (translation == null) { return(null); } _projectionMapping[_projectionMembers.Peek()] = translation; return(new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), expression.Type)); } } return(base.Visit(expression)); }
public override Expression Visit(Expression expression) { if (expression == null) { return(null); } if (!(expression is NewExpression || expression is MemberInitExpression || expression is EntityShaperExpression || expression is IncludeExpression)) { // This skips the group parameter from GroupJoin if (expression is ParameterExpression parameter && parameter.Type.IsGenericType && parameter.Type.GetGenericTypeDefinition() == typeof(IEnumerable <>)) { return(parameter); } if (_clientEval) { if (expression is ConstantExpression) { return(expression); } if (expression is ParameterExpression parameterExpression) { return(Expression.Call( _getParameterValueMethodInfo.MakeGenericMethod(parameterExpression.Type), QueryCompilationContext.QueryContextParameter, Expression.Constant(parameterExpression.Name))); } if (expression is MethodCallExpression methodCallExpression && methodCallExpression.Method.Name == "MaterializeCollectionNavigation") { var result = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression.Arguments[0]); var navigation = (INavigation)((ConstantExpression)methodCallExpression.Arguments[1]).Value; return(_selectExpression.AddCollectionProjection(result, navigation)); } var translation = _sqlTranslator.Translate(expression); if (translation == null) { return(base.Visit(expression)); } else { return(_selectExpression.AddToProjection(translation, expression.Type)); } } else { var translation = _sqlTranslator.Translate(expression); if (translation == null) { return(null); } _projectionMapping[_projectionMembers.Peek()] = translation; return(new ProjectionBindingExpression(_selectExpression, _projectionMembers.Peek(), expression.Type)); } } return(base.Visit(expression)); }
protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { // EF.Property case if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName)) { return(BindProperty(Visit(source), propertyName, methodCallExpression.Type)); } // Subquery case var subqueryTranslation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); if (subqueryTranslation != null) { var subquery = (InMemoryQueryExpression)subqueryTranslation.QueryExpression; if (subqueryTranslation.ResultType == ResultType.Enumerable) { return(null); } subquery.ApplyServerProjection(); if (subquery.Projection.Count != 1) { return(null); } Expression result; // Unwrap ResultEnumerable var selectMethod = (MethodCallExpression)subquery.ServerQueryExpression; var resultEnumerable = (NewExpression)selectMethod.Arguments[0]; var resultFunc = ((LambdaExpression)resultEnumerable.Arguments[0]).Body; // New ValueBuffer construct if (resultFunc is NewExpression newValueBufferExpression) { var innerExpression = ((NewArrayExpression)newValueBufferExpression.Arguments[0]).Expressions[0]; if (innerExpression is UnaryExpression unaryExpression && innerExpression.NodeType == ExpressionType.Convert && innerExpression.Type == typeof(object)) { result = unaryExpression.Operand; } else { result = innerExpression; } return(result.Type == methodCallExpression.Type ? result : Expression.Convert(result, methodCallExpression.Type)); } else { var selector = (LambdaExpression)selectMethod.Arguments[1]; var readValueExpression = ((NewArrayExpression)((NewExpression)selector.Body).Arguments[0]).Expressions[0]; if (readValueExpression is UnaryExpression unaryExpression2 && unaryExpression2.NodeType == ExpressionType.Convert && unaryExpression2.Type == typeof(object)) { readValueExpression = unaryExpression2.Operand; } var valueBufferVariable = Expression.Variable(typeof(ValueBuffer)); var replacedReadExpression = ReplacingExpressionVisitor.Replace( selector.Parameters[0], valueBufferVariable, readValueExpression); replacedReadExpression = replacedReadExpression.Type == methodCallExpression.Type ? replacedReadExpression : Expression.Convert(replacedReadExpression, methodCallExpression.Type); return(Expression.Block( variables: new[] { valueBufferVariable }, Expression.Assign(valueBufferVariable, resultFunc), Expression.Condition( Expression.MakeMemberAccess(valueBufferVariable, _valueBufferIsEmpty), Expression.Default(methodCallExpression.Type), replacedReadExpression))); } }
protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression) { if (methodCallExpression.TryGetEFPropertyArguments(out var source, out var propertyName)) { Type convertedType = null; if (source is UnaryExpression unaryExpression && unaryExpression.NodeType == ExpressionType.Convert) { source = unaryExpression.Operand; if (unaryExpression.Type != typeof(object)) { convertedType = unaryExpression.Type; } } if (source is EntityShaperExpression entityShaper) { var entityType = entityShaper.EntityType; if (convertedType != null) { entityType = entityType.RootType().GetDerivedTypesInclusive() .FirstOrDefault(et => et.ClrType == convertedType); } if (entityType != null) { var property = entityType.FindProperty(propertyName); return(BindProperty(entityShaper, property)); } } throw new InvalidOperationException(); } if (methodCallExpression.Method.DeclaringType == typeof(Queryable)) { var translation = _queryableMethodTranslatingExpressionVisitor.TranslateSubquery(methodCallExpression); var subquery = (SelectExpression)translation.QueryExpression; subquery.ApplyProjection(); if (methodCallExpression.Method.Name == nameof(Queryable.Any) || methodCallExpression.Method.Name == nameof(Queryable.All) || methodCallExpression.Method.Name == nameof(Queryable.Contains)) { if (subquery.Tables.Count == 0 && subquery.Projection.Count == 1) { return(subquery.Projection[0].Expression); } else { throw new InvalidOperationException(); } } else { return(new SubSelectExpression(subquery)); } } var @object = Visit(methodCallExpression.Object); if (TranslationFailed(methodCallExpression.Object, @object)) { return(null); } var arguments = new SqlExpression[methodCallExpression.Arguments.Count]; for (var i = 0; i < arguments.Length; i++) { var argument = Visit(methodCallExpression.Arguments[i]); if (TranslationFailed(methodCallExpression.Arguments[i], argument)) { return(null); } arguments[i] = (SqlExpression)argument; } return(_methodCallTranslatorProvider.Translate(_model, (SqlExpression)@object, methodCallExpression.Method, arguments)); }