public override Expression Visit(Expression node) { IEnumerable <string> GetNameParts() { return(nameStack.Reverse().Where(n => n != null && !n.StartsWith("<>"))); } switch (node) { case null: { return(null); } case NewExpression newExpression: { if (newExpression.Members == null) { return(newExpression); } var arguments = newExpression.Arguments.ToArray(); for (var i = 0; i < newExpression.Members.Count; i++) { nameStack.Push(newExpression.Members[i].GetPathSegmentName()); arguments[i] = Visit(arguments[i]); nameStack.Pop(); } return(newExpression.Update(arguments)); } case MemberInitExpression memberInitExpression: { var newExpression = (NewExpression)Visit(memberInitExpression.NewExpression); var bindings = memberInitExpression.Bindings.ToArray(); for (var i = 0; i < bindings.Length; i++) { nameStack.Push(bindings[i].Member.GetPathSegmentName()); bindings[i] = VisitMemberBinding(bindings[i]); nameStack.Pop(); } return(memberInitExpression.Update(newExpression, bindings)); } case ExtendedNewExpression newExpression: { var arguments = newExpression.Arguments.ToArray(); for (var i = 0; i < newExpression.Arguments.Count; i++) { nameStack.Push(newExpression.ReadableMembers[i].GetPathSegmentName()); arguments[i] = Visit(arguments[i]); nameStack.Pop(); } return(newExpression.Update(arguments)); } case ExtendedMemberInitExpression memberInitExpression: { var newExpression = (ExtendedNewExpression)Visit(memberInitExpression.NewExpression); var arguments = memberInitExpression.Arguments.ToArray(); for (var i = 0; i < arguments.Length; i++) { nameStack.Push(memberInitExpression.ReadableMembers[i].GetPathSegmentName()); arguments[i] = Visit(arguments[i]); nameStack.Pop(); } return(memberInitExpression.Update(newExpression, arguments)); } case NewArrayExpression newArrayExpression: { var expressions = new Expression[newArrayExpression.Expressions.Count]; for (var i = 0; i < newArrayExpression.Expressions.Count; i++) { nameStack.Push($"${i}"); expressions[i] = Visit(newArrayExpression.Expressions[i]); nameStack.Pop(); } return(newArrayExpression.Update(expressions)); } case GroupByResultExpression groupByResultExpression: { var uniquifier = new TableUniquifyingExpressionVisitor(); var oldSelectExpression = groupByResultExpression.SelectExpression; var newSelectExpression = uniquifier.VisitAndConvert(oldSelectExpression, nameof(Visit)); var oldTables = oldSelectExpression.Table.Flatten().ToArray(); var newTables = newSelectExpression.Table.Flatten().ToArray(); var updater = new TableUpdatingExpressionVisitor(oldTables, newTables); nameStack.Push("Key"); var outerKeySelector = Visit(groupByResultExpression.OuterKeySelector); var innerKeySelector = updater.Visit(groupByResultExpression.InnerKeySelector); var elementSelector = updater.Visit(groupByResultExpression.ElementSelector); nameStack.Pop(); return(new GroupedRelationalQueryExpression( newSelectExpression.UpdateProjection(new ServerProjectionExpression(elementSelector)), outerKeySelector, innerKeySelector, groupByResultExpression.InnerKeyLambda, requiresDenullification: false, type: groupByResultExpression.Type)); } case GroupedRelationalQueryExpression groupedRelationalQueryExpression: { var uniquifier = new TableUniquifyingExpressionVisitor(); var oldSelectExpression = groupedRelationalQueryExpression.SelectExpression; var newSelectExpression = uniquifier.VisitAndConvert(oldSelectExpression, nameof(Visit)); var oldTables = oldSelectExpression.Table.Flatten().ToArray(); var newTables = newSelectExpression.Table.Flatten().ToArray(); var updater = new TableUpdatingExpressionVisitor(oldTables, newTables); nameStack.Push("Key"); var outerKeySelector = Visit(groupedRelationalQueryExpression.OuterKeySelector); var innerKeySelector = updater.Visit(groupedRelationalQueryExpression.InnerKeySelector); nameStack.Pop(); return(new GroupedRelationalQueryExpression( newSelectExpression, outerKeySelector, innerKeySelector, groupedRelationalQueryExpression.InnerKeyLambda, groupedRelationalQueryExpression.RequiresDenullification, groupedRelationalQueryExpression.Type)); } case DefaultIfEmptyExpression defaultIfEmptyExpression: { var expression = new SqlColumnNullabilityExpressionVisitor(true) .Visit(Visit(defaultIfEmptyExpression.Expression)); var name = string.Join(".", GetNameParts().Append("$empty")); var flag = new SqlColumnExpression(targetTable, name, typeof(bool?), true, null); return(new DefaultIfEmptyExpression(expression, flag)); } case PolymorphicExpression polymorphicExpression: { var row = Visit(polymorphicExpression.Row); // TODO: Visit nested polymorphic expressions. return(new PolymorphicExpression( polymorphicExpression.Type, row, polymorphicExpression.Descriptors)); } case ExtraPropertiesExpression extraPropertiesExpression: { var properties = new Expression[extraPropertiesExpression.Properties.Count]; for (var i = 0; i < extraPropertiesExpression.Properties.Count; i++) { var path = extraPropertiesExpression.GetMemberPath(i).ToArray(); if (path.Length == 0) { nameStack.Push(extraPropertiesExpression.Names[i]); properties[i] = Visit(extraPropertiesExpression.Properties[i]); nameStack.Pop(); } else { for (var j = 0; j < path.Length; j++) { nameStack.Push(path[j].GetPathSegmentName()); } properties[i] = Visit(extraPropertiesExpression.Properties[i]); for (var j = 0; j < path.Length; j++) { nameStack.Pop(); } } } var expression = Visit(extraPropertiesExpression.Expression); return(extraPropertiesExpression.Update(expression, properties)); } case LateBoundProjectionLeafExpression _: { return(node); } case AnnotationExpression annotationExpression: { return(base.Visit(annotationExpression)); } case UnaryExpression unaryExpression when unaryExpression.NodeType == ExpressionType.Convert: { return(unaryExpression.Update(Visit(unaryExpression.Operand))); } default: { var parts = GetNameParts(); var isNullable = node.Type.IsNullableType(); var typeMapping = default(ITypeMapping); switch (node) { case SqlColumnExpression sqlColumnExpression: { parts = parts.DefaultIfEmpty(sqlColumnExpression.ColumnName); isNullable = sqlColumnExpression.IsNullable; typeMapping = sqlColumnExpression.TypeMapping; break; } case SqlAliasExpression sqlAliasExpression: { parts = parts.DefaultIfEmpty(sqlAliasExpression.Alias); break; } } return(new SqlColumnExpression( targetTable, string.Join(".", parts), node.Type, isNullable, typeMapping)); } } }
public override Expression Visit(Expression node) { var visited = base.Visit(node); switch (visited) { case GroupByResultExpression groupByResultExpression: { var uniquifier = new TableUniquifyingExpressionVisitor(); var oldSelectExpression = groupByResultExpression.SelectExpression; var newSelectExpression = uniquifier.VisitAndConvert(oldSelectExpression, nameof(VisitMethodCall)); var oldTables = oldSelectExpression.Table.Flatten().ToArray(); var newTables = newSelectExpression.Table.Flatten().ToArray(); var updater = new TableUpdatingExpressionVisitor(oldTables, newTables); var outerKeySelector = groupByResultExpression.OuterKeySelector; var innerKeySelector = updater.Visit(groupByResultExpression.InnerKeySelector); var elementSelector = updater.Visit(groupByResultExpression.ElementSelector); if (IsTranslatable(outerKeySelector) && IsTranslatable(innerKeySelector) && IsTranslatable(elementSelector)) { var projection = elementSelector .VisitWith(postExpansionVisitors); var predicate = Expression .Equal(outerKeySelector, innerKeySelector) .VisitWith(postExpansionVisitors); var query = new EnumerableRelationalQueryExpression( newSelectExpression .UpdateProjection(new ServerProjectionExpression(projection)) .AddToPredicate(predicate)); return(ExpandedGrouping.Create( groupByResultExpression.Type, groupByResultExpression.OuterKeySelector, query.AsList())); } else { throw new NotImplementedException(); } } case GroupedRelationalQueryExpression groupedRelationalQueryExpression: { var outerKeySelector = groupedRelationalQueryExpression.OuterKeySelector; var innerKeySelector = groupedRelationalQueryExpression.InnerKeySelector; if (IsTranslatable(outerKeySelector) && IsTranslatable(innerKeySelector)) { if (groupedRelationalQueryExpression.RequiresDenullification) { outerKeySelector = JoinKeyDenullifyingExpressionVisitor.Instance.Visit(outerKeySelector); innerKeySelector = JoinKeyDenullifyingExpressionVisitor.Instance.Visit(innerKeySelector); } var predicate = Expression .Equal(outerKeySelector, innerKeySelector) .VisitWith(postExpansionVisitors); var query = new EnumerableRelationalQueryExpression( groupedRelationalQueryExpression.SelectExpression .AddToPredicate(predicate)); return(ExpandedGrouping.Create( groupedRelationalQueryExpression.Type, groupedRelationalQueryExpression.OuterKeySelector, query.AsList())); } else { var predicate = Expression.Lambda( Expression.Equal( outerKeySelector, groupedRelationalQueryExpression.InnerKeyLambda.Body), groupedRelationalQueryExpression.InnerKeyLambda.Parameters); return(Expression.Call( queryableWhere.MakeGenericMethod(groupedRelationalQueryExpression.Type.GetSequenceType()), new EnumerableRelationalQueryExpression(groupedRelationalQueryExpression.SelectExpression), Expression.Quote(predicate))); } } default: { return(visited); } } }