Пример #1
0
        private static Expression CreateForeignKeyMemberAccess(string propertyName, Expression declaringExpression, INavigation navigation)
        {
            var principalKey = navigation.ForeignKey.PrincipalKey;

            if (principalKey.Properties.Count == 1)
            {
                Debug.Assert(navigation.ForeignKey.Properties.Count == 1);

                var principalKeyProperty = principalKey.Properties[0];
                if (principalKeyProperty.Name == propertyName &&
                    principalKeyProperty.ClrType == navigation.ForeignKey.Properties[0].ClrType)
                {
                    var declaringMethodCallExpression = declaringExpression as MethodCallExpression;
                    var parentDeclaringExpression     = declaringMethodCallExpression != null &&
                                                        EntityQueryModelVisitor.IsPropertyMethod(declaringMethodCallExpression.Method)
                        ? declaringMethodCallExpression.Arguments[0]
                        : (declaringExpression as MemberExpression)?.Expression;

                    if (parentDeclaringExpression != null)
                    {
                        var foreignKeyPropertyExpression = CreateKeyAccessExpression(parentDeclaringExpression, navigation.ForeignKey.Properties);

                        return(foreignKeyPropertyExpression);
                    }
                }
            }

            return(null);
        }
        /// <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 newMethodCallExpression = (MethodCallExpression)base.VisitMethodCall(methodCallExpression);

            if (EntityQueryModelVisitor.IsPropertyMethod(methodCallExpression.Method))
            {
                var subQueryExpression = newMethodCallExpression.Arguments[0] as SubQueryExpression;
                var subSelector        = subQueryExpression?.QueryModel.SelectClause.Selector as QuerySourceReferenceExpression;

                if (subSelector != null)
                {
                    var subQueryModel = subQueryExpression.QueryModel;

                    subQueryModel.SelectClause.Selector
                        = methodCallExpression
                          .Update(
                              null,
                              new[]
                    {
                        subSelector,
                        methodCallExpression.Arguments[1]
                    });

                    subQueryModel.ResultTypeOverride = subQueryModel.SelectClause.Selector.Type;

                    return(new SubQueryExpression(subQueryModel));
                }
            }

            return(newMethodCallExpression);
        }
            protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)
            {
                if (EntityQueryModelVisitor.IsPropertyMethod(methodCallExpression.Method))
                {
                    _requiresBuffering = true;

                    return(methodCallExpression);
                }

                return(base.VisitMethodCall(methodCallExpression));
            }
Пример #4
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            var referenceSource = node.Arguments.FirstOrDefault() as QuerySourceReferenceExpression;

            if (EntityQueryModelVisitor.IsPropertyMethod(node.Method) &&
                referenceSource?.ReferencedQuerySource.Equals(_targetQuerySource) == true)
            {
                return(node);
            }
            return(base.VisitMethodCall(node));
        }
Пример #5
0
        /// <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 VisitBinary(BinaryExpression node)
        {
            var leftConstantExpression = node.Left.RemoveConvert() as ConstantExpression;
            var isLeftNullConstant     = leftConstantExpression != null && leftConstantExpression.Value == null;

            var rightConstantExpression = node.Right.RemoveConvert() as ConstantExpression;
            var isRightNullConstant     = rightConstantExpression != null && rightConstantExpression.Value == null;

            if (isLeftNullConstant || isRightNullConstant)
            {
                var nonNullExpression = isLeftNullConstant ? node.Right : node.Left;

                var methodCallExpression = nonNullExpression as MethodCallExpression;
                if (methodCallExpression != null)
                {
                    if (EntityQueryModelVisitor.IsPropertyMethod(methodCallExpression.Method))
                    {
                        var firstArgument   = methodCallExpression.Arguments[0];
                        var visitedArgument = Visit(firstArgument);
                        if (visitedArgument.Type == typeof(ValueBuffer))
                        {
                            var nullCheck = ValueBufferNullComparisonCheck(visitedArgument);
                            var propertyAccessExpression = Visit(nonNullExpression);

                            return(Expression.MakeBinary(
                                       node.NodeType,
                                       Expression.Condition(
                                           nullCheck,
                                           propertyAccessExpression,
                                           Expression.Constant(null, propertyAccessExpression.Type)),
                                       Expression.Constant(null)));
                        }
                    }
                }
            }

            var newLeft  = Visit(node.Left);
            var newRight = Visit(node.Right);

            if (newLeft.Type == typeof(ValueBuffer))
            {
                newLeft = _queryModelVisitor.BindReadValueMethod(node.Left.Type, newLeft, 0);
            }

            if (newRight.Type == typeof(ValueBuffer))
            {
                newRight = _queryModelVisitor.BindReadValueMethod(node.Right.Type, newRight, 0);
            }

            var newConversion = VisitAndConvert(node.Conversion, "VisitBinary");

            return(node.Update(newLeft, newConversion, newRight));
        }
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            MethodCallExpression newExpression = null;
            Expression           firstArgument = null;

            if (EntityQueryModelVisitor.IsPropertyMethod(node.Method))
            {
                var newArguments
                    = VisitAndConvert(node.Arguments, "VisitMethodCall");

                if (newArguments[0].Type == typeof(ValueBuffer))
                {
                    firstArgument = newArguments[0];

                    // Compensate for ValueBuffer being a struct, and hence not compatible with Object method
                    newExpression
                        = Expression.Call(
                              node.Method,
                              Expression.Convert(newArguments[0], typeof(object)),
                              newArguments[1]);
                }
            }

            if (newExpression == null)
            {
                newExpression
                    = (MethodCallExpression)base.VisitMethodCall(node);
            }

            firstArgument = firstArgument ?? newExpression.Arguments.FirstOrDefault();

            if ((newExpression != node) &&
                (firstArgument?.Type == typeof(ValueBuffer)))
            {
                return
                    (_queryModelVisitor
                     .BindMethodCallToValueBuffer(node, firstArgument)
                     ?? newExpression);
            }

            return(_queryModelVisitor
                   .BindMethodCallExpression(
                       node,
                       (property, _) => Expression.Call(
                           _getValueMethodInfo.MakeGenericMethod(newExpression.Method.GetGenericArguments()[0]),
                           EntityQueryModelVisitor.QueryContextParameter,
                           newExpression.Arguments[0],
                           Expression.Constant(property)))
                   ?? newExpression);
        }
            private void AnalyzeTestExpression(Expression expression)
            {
                var querySourceReferenceExpression = expression as QuerySourceReferenceExpression;

                if (querySourceReferenceExpression != null)
                {
                    _querySource  = querySourceReferenceExpression.ReferencedQuerySource;
                    _propertyName = null;

                    return;
                }

                var memberExpression = expression as MemberExpression;

                if (memberExpression != null)
                {
                    var querySourceInstance = memberExpression.Expression as QuerySourceReferenceExpression;
                    if (querySourceInstance != null)
                    {
                        _querySource  = querySourceInstance.ReferencedQuerySource;
                        _propertyName = memberExpression.Member.Name;

                        return;
                    }
                }

                var methodCallExpression = expression as MethodCallExpression;

                if (methodCallExpression != null && EntityQueryModelVisitor.IsPropertyMethod(methodCallExpression.Method))
                {
                    var querySourceCaller = methodCallExpression.Arguments[0] as QuerySourceReferenceExpression;
                    if (querySourceCaller != null)
                    {
                        var propertyNameExpression = methodCallExpression.Arguments[1] as ConstantExpression;
                        if (propertyNameExpression != null)
                        {
                            _querySource  = querySourceCaller.ReferencedQuerySource;
                            _propertyName = (string)propertyNameExpression.Value;

                            return;
                        }
                    }
                }
            }
            protected override Expression VisitMethodCall(MethodCallExpression node)
            {
                if (EntityQueryModelVisitor.IsPropertyMethod(node.Method))
                {
                    var propertyNameExpression = node.Arguments[1] as ConstantExpression;
                    if (propertyNameExpression != null && (string)propertyNameExpression.Value == _propertyName)
                    {
                        var querySource = node.Arguments[0] as QuerySourceReferenceExpression;
                        if (querySource != null)
                        {
                            _canRemoveNullCheck = querySource.ReferencedQuerySource == _querySource;

                            return(node);
                        }
                    }
                }

                return(base.VisitMethodCall(node));
            }
Пример #9
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            Check.NotNull(node, nameof(node));

            if (EntityQueryModelVisitor.IsPropertyMethod(node.Method))
            {
                var newArg0 = Visit(node.Arguments[0]);

                if (newArg0 != node.Arguments[0])
                {
                    return(Expression.Call(
                               node.Method,
                               newArg0,
                               node.Arguments[1]));
                }

                return(node);
            }

            return(base.VisitMethodCall(node));
        }
Пример #10
0
        private Expression TryRemoveNullCheck(ConditionalExpression node)
        {
            var binaryTest = node.Test as BinaryExpression;

            if (binaryTest == null ||
                binaryTest.NodeType != ExpressionType.NotEqual)
            {
                return(null);
            }

            var rightConstant = binaryTest.Right as ConstantExpression;

            if (rightConstant == null ||
                rightConstant.Value != null)
            {
                return(null);
            }

            var ifFalseConstant = node.IfFalse as ConstantExpression;

            if (ifFalseConstant == null ||
                ifFalseConstant.Value != null)
            {
                return(null);
            }

            var ifTrueMemberExpression  = node.IfTrue.RemoveConvert() as MemberExpression;
            var correctMemberExpression = ifTrueMemberExpression != null &&
                                          ifTrueMemberExpression.Expression == binaryTest.Left;

            var ifTruePropertyMethodCallExpression  = node.IfTrue.RemoveConvert() as MethodCallExpression;
            var correctPropertyMethodCallExpression = ifTruePropertyMethodCallExpression != null &&
                                                      EntityQueryModelVisitor.IsPropertyMethod(ifTruePropertyMethodCallExpression.Method) &&
                                                      ifTruePropertyMethodCallExpression.Arguments[0] == binaryTest.Left;

            return(correctMemberExpression || correctPropertyMethodCallExpression ? node.IfTrue : null);
        }
Пример #11
0
        /// <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 node)
        {
            Check.NotNull(node, nameof(node));

            if (!EntityQueryModelVisitor.IsPropertyMethod(node.Method))
            {
                base.VisitMethodCall(node);
            }

            return
                (_queryModelVisitor.BindNavigationPathPropertyExpression(
                     node,
                     (ps, qs) =>
            {
                return RewriteNavigationProperties(
                    ps.ToList(),
                    qs,
                    node.Arguments[0],
                    (string)(node.Arguments[1] as ConstantExpression).Value,
                    node.Type,
                    e => Expression.Call(node.Method, e, node.Arguments[1]));
            })
                 ?? base.VisitMethodCall(node));
        }
        protected override Expression VisitSubQuery(SubQueryExpression expression)
        {
            Check.NotNull(expression, nameof(expression));

            var subQueryModel = expression.QueryModel;

            if (subQueryModel.IsIdentityQuery() &&
                subQueryModel.ResultOperators.Count == 1)
            {
                var contains = subQueryModel.ResultOperators.First() as ContainsResultOperator;

                if (contains != null)
                {
                    var fromExpression = subQueryModel.MainFromClause.FromExpression;

                    if (fromExpression.NodeType == ExpressionType.Parameter ||
                        fromExpression.NodeType == ExpressionType.Constant ||
                        fromExpression.NodeType == ExpressionType.ListInit ||
                        fromExpression.NodeType == ExpressionType.NewArrayInit)
                    {
                        var memberItem = contains.Item as MemberExpression;

                        if (memberItem != null)
                        {
                            var aliasExpression = VisitMember(memberItem) as AliasExpression;

                            return(aliasExpression != null
                                ? new InExpression(aliasExpression, new[] { fromExpression })
                                : null);
                        }

                        var methodCallItem = contains.Item as MethodCallExpression;

                        if (methodCallItem != null &&
                            EntityQueryModelVisitor.IsPropertyMethod(methodCallItem.Method))
                        {
                            var aliasExpression = (AliasExpression)VisitMethodCall(methodCallItem);

                            return(new InExpression(aliasExpression, new[] { fromExpression }));
                        }
                    }
                }
            }
            else if (!(subQueryModel.GetOutputDataInfo() is StreamedSequenceInfo))
            {
                if (_inProjection &&
                    !(subQueryModel.GetOutputDataInfo() is StreamedScalarValueInfo))
                {
                    return(null);
                }

                var querySourceReferenceExpression
                    = subQueryModel.SelectClause.Selector as QuerySourceReferenceExpression;

                if (querySourceReferenceExpression == null ||
                    _inProjection ||
                    !_queryModelVisitor.QueryCompilationContext
                    .QuerySourceRequiresMaterialization(querySourceReferenceExpression.ReferencedQuerySource))
                {
                    var queryModelVisitor
                        = (RelationalQueryModelVisitor)_queryModelVisitor.QueryCompilationContext
                          .CreateQueryModelVisitor(_queryModelVisitor);

                    queryModelVisitor.VisitSubQueryModel(subQueryModel);

                    if (queryModelVisitor.Queries.Count == 1 &&
                        !queryModelVisitor.RequiresClientFilter &&
                        !queryModelVisitor.RequiresClientProjection &&
                        !queryModelVisitor.RequiresClientResultOperator)
                    {
                        var selectExpression = queryModelVisitor.Queries.First();

                        selectExpression.Alias = string.Empty; // anonymous

                        var containsResultOperator
                            = subQueryModel.ResultOperators.LastOrDefault() as ContainsResultOperator;

                        if (containsResultOperator != null)
                        {
                            var itemExpression = Visit(containsResultOperator.Item) as AliasExpression;

                            if (itemExpression != null)
                            {
                                return(new InExpression(itemExpression, selectExpression));
                            }
                        }

                        return(selectExpression);
                    }
                }
            }

            return(null);
        }
Пример #13
0
        /// <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)
        {
            MethodCallExpression newExpression = null;
            Expression           firstArgument = null;

            if (EntityQueryModelVisitor.IsPropertyMethod(methodCallExpression.Method))
            {
                var newArguments
                    = VisitAndConvert(
                          new List <Expression>
                {
                    methodCallExpression.Arguments[0].RemoveConvert(),
                    methodCallExpression.Arguments[1]
                }.AsReadOnly(),
                          "VisitMethodCall");

                if (newArguments[0].Type == typeof(ValueBuffer))
                {
                    firstArgument = newArguments[0];

                    // Compensate for ValueBuffer being a struct, and hence not compatible with Object method
                    newExpression
                        = Expression.Call(
                              methodCallExpression.Method,
                              Expression.Convert(newArguments[0], typeof(object)),
                              newArguments[1]);
                }
            }

            if (newExpression == null)
            {
                newExpression
                    = (MethodCallExpression)base.VisitMethodCall(methodCallExpression);
            }

            firstArgument = firstArgument ?? newExpression.Arguments.FirstOrDefault();

            if (newExpression != methodCallExpression &&
                firstArgument?.Type == typeof(ValueBuffer))
            {
                return
                    (_queryModelVisitor
                     .BindMethodCallToValueBuffer(methodCallExpression, firstArgument)
                     ?? newExpression);
            }

            return(_queryModelVisitor
                   .BindMethodCallExpression <Expression>(
                       methodCallExpression,
                       (property, _) =>
            {
                var propertyType = newExpression.Method.GetGenericArguments()[0];

                var maybeConstantExpression = newExpression.Arguments[0] as ConstantExpression;

                if (maybeConstantExpression != null)
                {
                    return Expression.Constant(
                        property.GetGetter().GetClrValue(maybeConstantExpression.Value),
                        propertyType);
                }

                var maybeMethodCallExpression = newExpression.Arguments[0] as MethodCallExpression;

                if (maybeMethodCallExpression != null &&
                    maybeMethodCallExpression.Method.IsGenericMethod &&
                    maybeMethodCallExpression.Method.GetGenericMethodDefinition()
                    .Equals(DefaultQueryExpressionVisitor.GetParameterValueMethodInfo) ||
                    (newExpression.Arguments[0].NodeType == ExpressionType.Parameter &&
                     !property.IsShadowProperty))
                {
                    // The target is a parameter, try and get the value from it directly.
                    return Expression.Call(
                        _getValueFromEntityMethodInfo
                        .MakeGenericMethod(propertyType),
                        Expression.Constant(property.GetGetter()),
                        newExpression.Arguments[0]);
                }

                return Expression.Call(
                    _getValueMethodInfo.MakeGenericMethod(propertyType),
                    EntityQueryModelVisitor.QueryContextParameter,
                    newExpression.Arguments[0],
                    Expression.Constant(property));
            })
                   ?? newExpression);
        }
        /// <summary>
        ///     Visits a sub-query expression.
        /// </summary>
        /// <param name="expression"> The expression to visit. </param>
        /// <returns>
        ///     An Expression.
        /// </returns>
        protected override Expression VisitSubQuery(SubQueryExpression expression)
        {
            Check.NotNull(expression, nameof(expression));

            var subQueryModel = expression.QueryModel;

            var subQueryOutputDataInfo = subQueryModel.GetOutputDataInfo();

            if (subQueryModel.IsIdentityQuery() &&
                subQueryModel.ResultOperators.Count == 1 &&
                subQueryModel.ResultOperators.First() is ContainsResultOperator)
            {
                var contains       = (ContainsResultOperator)subQueryModel.ResultOperators.First();
                var fromExpression = subQueryModel.MainFromClause.FromExpression;

                if (fromExpression.NodeType == ExpressionType.Parameter ||
                    fromExpression.NodeType == ExpressionType.Constant ||
                    fromExpression.NodeType == ExpressionType.ListInit ||
                    fromExpression.NodeType == ExpressionType.NewArrayInit)
                {
                    var memberItem = contains.Item as MemberExpression;

                    if (memberItem != null)
                    {
                        var aliasExpression = VisitMember(memberItem) as AliasExpression;

                        return(aliasExpression != null
                            ? new InExpression(aliasExpression, new[] { fromExpression })
                            : null);
                    }

                    var methodCallItem = contains.Item as MethodCallExpression;

                    if (methodCallItem != null &&
                        EntityQueryModelVisitor.IsPropertyMethod(methodCallItem.Method))
                    {
                        var aliasExpression = (AliasExpression)VisitMethodCall(methodCallItem);

                        return(new InExpression(aliasExpression, new[] { fromExpression }));
                    }
                }
            }
            else if (!(subQueryOutputDataInfo is StreamedSequenceInfo))
            {
                var streamedSingleValueInfo          = subQueryOutputDataInfo as StreamedSingleValueInfo;
                var streamedSingleValueSupportedType = streamedSingleValueInfo != null &&
                                                       _relationalTypeMapper.FindMapping(streamedSingleValueInfo.DataType.UnwrapNullableType().UnwrapEnumType()) != null;

                if (_inProjection &&
                    !(subQueryOutputDataInfo is StreamedScalarValueInfo) &&
                    !streamedSingleValueSupportedType)
                {
                    return(null);
                }

                var querySourceReferenceExpression
                    = subQueryModel.SelectClause.Selector as QuerySourceReferenceExpression;

                if (querySourceReferenceExpression == null ||
                    _inProjection ||
                    !_queryModelVisitor.QueryCompilationContext
                    .QuerySourceRequiresMaterialization(querySourceReferenceExpression.ReferencedQuerySource))
                {
                    var queryModelVisitor
                        = (RelationalQueryModelVisitor)_queryModelVisitor.QueryCompilationContext
                          .CreateQueryModelVisitor(_queryModelVisitor);

                    var queriesProjectionCountMapping = _queryModelVisitor.Queries
                                                        .ToDictionary(k => k, s => s.Projection.Count);

                    queryModelVisitor.VisitSubQueryModel(subQueryModel);

                    if (queryModelVisitor.Queries.Count == 1 &&
                        !queryModelVisitor.RequiresClientFilter &&
                        !queryModelVisitor.RequiresClientProjection &&
                        !queryModelVisitor.RequiresClientResultOperator)
                    {
                        var selectExpression = queryModelVisitor.Queries.First();

                        selectExpression.Alias = string.Empty; // anonymous

                        foreach (var mappingElement in queriesProjectionCountMapping)
                        {
                            mappingElement.Key.RemoveRangeFromProjection(mappingElement.Value);
                        }

                        return(selectExpression);
                    }
                }
            }

            return(null);
        }
Пример #15
0
 protected override Expression VisitMethodCall(MethodCallExpression expression)
 => EntityQueryModelVisitor.IsPropertyMethod(expression.Method)
         ? Expression.Property(
     expression.Arguments[0].RemoveConvert(),
     Expression.Lambda <Func <string> >(expression.Arguments[1]).Compile().Invoke())
         : base.VisitMethodCall(expression);
Пример #16
0
        /// <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 node)
        {
            var simpleMethods = new List <string>
            {
                "get_Item",
                "TryReadValue"
            };

            switch (node.Method.Name)
            {
            case "_InterceptExceptions":
                Visit(node.Arguments[0]);

                return(node);

            case "_TrackEntities":
                TrackedQuery = true;
                Visit(node.Arguments[0]);

                return(node);
            }

            if (!EntityQueryModelVisitor.IsPropertyMethod(node.Method))
            {
                _stringBuilder.Append(node.Method.ReturnType.ShortDisplayName() + " ");
            }

            if (node.Object != null)
            {
                Visit(node.Object);
                _stringBuilder.Append(".");
            }

            _stringBuilder.Append(node.Method.Name + "(");

            var appendAction = simpleMethods.Contains(node.Method.Name) || EntityQueryModelVisitor.IsPropertyMethod(node.Method)
                ? (Action <string>)Append
                : AppendLine;

            if (node.Arguments.Count > 0)
            {
                appendAction("");

                var showArgumentNames = !simpleMethods.Contains(node.Method.Name) && !EntityQueryModelVisitor.IsPropertyMethod(node.Method);
                var argumentNames     = showArgumentNames ? node.Method.GetParameters().Select(p => p.Name).ToList() : new List <string>();

                _stringBuilder.IncrementIndent();
                for (var i = 0; i < node.Arguments.Count; i++)
                {
                    var argument = node.Arguments[i];

                    if (showArgumentNames)
                    {
                        _stringBuilder.Append(argumentNames[i] + ": ");
                    }

                    Visit(argument);

                    appendAction(i == node.Arguments.Count - 1 ? "" : ", ");
                }

                _stringBuilder.DecrementIndent();
            }

            appendAction(")");

            return(node);
        }