protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            Expression expression = base.Visit(node.Arguments[0]);

            if (node.Method.DeclaringType == typeof(EntityFrameworkQueryableExtensions))
            {
                if (node.Method.Name == nameof(EntityFrameworkQueryableExtensions.Include) ||
                    node.Method.Name == nameof(EntityFrameworkQueryableExtensions.ThenInclude))
                {
                    var visitor = new PropertyVisitor();
                    visitor.Visit(node.Arguments[1]);

                    if (visitor.Filter == null)
                    {
                        node = Expression.Call(null, node.Method, new Expression[] { expression, node.Arguments[1] });
                    }
                    else
                    {
                        if (node.Method.Name == nameof(EntityFrameworkQueryableExtensions.Include))
                        {
                            Type             entityType = node.Method.GetGenericArguments()[0];
                            MethodInfo       method     = node.Method.GetGenericMethodDefinition().MakeGenericMethod(entityType, visitor.Property.Type);
                            LambdaExpression lambda     = Expression.Lambda(visitor.Property, visitor.Parameter);
                            node = Expression.Call(null, method, new Expression[] { node.Arguments[0], lambda });
                        }
                        else
                        {
                            Type             entityType           = node.Method.GetGenericArguments()[0];
                            Type             previousPropertyType = node.Method.GetGenericArguments()[1];
                            MethodInfo       method = node.Method.GetGenericMethodDefinition().MakeGenericMethod(entityType, previousPropertyType, visitor.Property.Type);
                            LambdaExpression lambda = Expression.Lambda(visitor.Property, visitor.Parameter);
                            node = Expression.Call(null, method, new Expression[] { node.Arguments[0], lambda });
                        }
                    }

                    _includes.Add(new Include(visitor.Property.Member as PropertyInfo, visitor.Filter, false));
                }
            }
            else if (node.Method.DeclaringType == typeof(Queryable) && node.Method.Name == nameof(Queryable.Select))
            {
                var visitor = new NewVisitor();
                visitor.Visit(node.Arguments[1]);
                _includes.AddRange(visitor.SelectProperties.Select(p => new Include(p, null, true)));
            }
            else
            {
                if (node.Arguments.Count == 1)
                {
                    node = Expression.Call(node.Object, node.Method, expression);
                }
                else
                {
                    node = Expression.Call(node.Object, node.Method, expression, node.Arguments[1]);
                }
            }
            return(node);
        }
Example #2
0
        static void ShowVisitorPattern()
        {
            List <BallBase> ballBases = new List <BallBase>()
            {
                new BasketBall(),
                new BasketBall(),
                new FootBall(),
                new BasketBall(),
                new FootBall()
            };
            BallVisitorBase oldVisitor = new OldVisitor();

            foreach (var ball in ballBases)
            {
                ball.Play(oldVisitor);
            }
            Console.WriteLine("=========================================");
            BallVisitorBase newVisitor = new NewVisitor();

            foreach (var ball in ballBases)
            {
                ball.Play(newVisitor);
            }
        }
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            Expression expression = base.Visit(node.Arguments[0]);

            if (node.Method.DeclaringType == typeof(EntityFrameworkQueryableExtensions))
            {
                if (node.Method.Name == nameof(EntityFrameworkQueryableExtensions.Include) ||
                    node.Method.Name == nameof(EntityFrameworkQueryableExtensions.ThenInclude))
                {
                    var visitor = new PropertyVisitor(_isDatabaseNullHighestValue);
                    visitor.Visit(node.Arguments[1]);

                    if (_metadataProvider.IsNotMapped((PropertyInfo)visitor.PropertyExpression.Member))
                    {
                        _includes.Add(new EfInclude(visitor.PropertyExpression.Member as PropertyInfo, visitor.Filter, visitor.IsOrdered));
                        return(node.Arguments[0]);
                    }

                    if (visitor.Filter == null)
                    {
                        node = Expression.Call(null, node.Method, new Expression[] { expression, node.Arguments[1] });
                    }
                    else
                    {
                        Type       entityType = node.Method.GetGenericArguments()[0];
                        MethodInfo method;
                        if (node.Method.Name == nameof(EntityFrameworkQueryableExtensions.Include))
                        {
                            method = node.Method.GetGenericMethodDefinition().MakeGenericMethod(entityType, visitor.PropertyExpression.Type);
                        }
                        else
                        {
                            Type previousPropertyType = node.Method.GetGenericArguments()[1];
                            method = node.Method.GetGenericMethodDefinition().MakeGenericMethod(entityType, previousPropertyType, visitor.PropertyExpression.Type);
                        }
                        LambdaExpression lambda = Expression.Lambda(visitor.PropertyExpression, visitor.Parameter);
                        node = Expression.Call(null, method, new Expression[] { expression, lambda });
                    }

                    PropertyInfo parentProperty = null;
                    if (node.Method.Name == nameof(EntityFrameworkQueryableExtensions.ThenInclude))
                    {
                        var parentVisitor = new PropertyVisitor(_isDatabaseNullHighestValue);
                        parentVisitor.Visit(node.Arguments[0]);
                        parentProperty = parentVisitor.PropertyExpression.Member as PropertyInfo;
                    }

                    _includes.Add(new EfInclude(visitor.PropertyExpression.Member as PropertyInfo, visitor.Filter, visitor.IsOrdered, parentProperty));
                    return(node);
                }
            }
            else if (node.Method.DeclaringType == typeof(Queryable) && node.Method.Name == nameof(Queryable.Select))
            {
                var visitor = new NewVisitor();
                visitor.Visit(node.Arguments[1]);
                _includes.AddRange(visitor.SelectProperties.Select(p => new EfInclude(p, null, false)));
            }
            else if (node.Method.DeclaringType == typeof(Queryable) && node.Method.Name == nameof(Queryable.GroupJoin))
            {
                Type outerType = node.Arguments[0].Type.GetGenericArguments()[0];
                Type innerType = node.Arguments[1].Type.GetGenericArguments()[0];

                List <PropertyInfo> navigationProperties = outerType.GetProperties().Where(p => p.PropertyType == innerType).ToList();
                if (navigationProperties.Count == 0)
                {
                    Type         collectionType     = typeof(IEnumerable <>).MakeGenericType(innerType);
                    PropertyInfo navigationProperty = outerType.GetProperties().Where(p => collectionType.IsAssignableFrom(p.PropertyType)).Single();
                    _includes.Add(new EfInclude(navigationProperty, null, false));
                }
                else if (navigationProperties.Count == 1)
                {
                    _includes.Add(new EfInclude(navigationProperties[0], null, false));
                }
                else
                {
                    LambdaExpression outerKeySelector;
                    if (node.Arguments[2] is UnaryExpression unaryExpression)
                    {
                        outerKeySelector = (LambdaExpression)unaryExpression.Operand;
                    }
                    else
                    {
                        outerKeySelector = (LambdaExpression)node.Arguments[2];
                    }

                    if (outerKeySelector.Body is MemberExpression propertyExpression)
                    {
                        PropertyInfo navigationProperty = _metadataProvider.GetForeignKey((PropertyInfo)propertyExpression.Member).Single();
                        _includes.Add(new EfInclude(navigationProperty, null, false));
                    }
                    else if (outerKeySelector.Body is NewExpression newExpression)
                    {
                        List <PropertyInfo> properties = newExpression.Arguments.Select(a => (PropertyInfo)((MemberExpression)a).Member).ToList();
                        foreach (PropertyInfo navigationProperty in navigationProperties)
                        {
                            PropertyInfo[] structuralProperties = _metadataProvider.GetForeignKey(navigationProperty);
                            if (!structuralProperties.Except(properties).Any())
                            {
                                _includes.Add(new EfInclude(navigationProperty, null, false));
                                break;
                            }
                        }
                    }
                }
            }

            var arguments = new Expression[node.Arguments.Count];

            node.Arguments.CopyTo(arguments, 0);
            arguments[0] = expression;
            return(Expression.Call(node.Object, node.Method, arguments));
        }