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); }
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)); }