public static Expression Create( Type type, Expression keyExpression, EnumerableRelationalQueryExpression elementsExpression) { if (type.IsGenericType(typeof(IGrouping <,>))) { var expandedGroupingType = typeof(ExpandedGrouping <,>) .MakeGenericType(type.GenericTypeArguments); return(Expression.New( expandedGroupingType.GetTypeInfo().DeclaredConstructors.Single(), new[] { keyExpression, elementsExpression }, new[] { expandedGroupingType.GetRuntimeProperty("Key"), expandedGroupingType.GetRuntimeProperty("Elements") })); } else { return(elementsExpression); } }
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); var elements = new EnumerableRelationalQueryExpression( newSelectExpression .UpdateProjection(new ServerProjectionExpression(elementSelector)) .AddToPredicate(Expression.Equal(outerKeySelector, innerKeySelector))); return(ExpandGroup(visited, outerKeySelector, elements)); } case GroupedRelationalQueryExpression groupedRelationalQueryExpression: { var outerKeySelector = groupedRelationalQueryExpression.OuterKeySelector; var innerKeySelector = groupedRelationalQueryExpression.InnerKeySelector; if (groupedRelationalQueryExpression.RequiresDenullification) { outerKeySelector = JoinKeyDenullifyingExpressionVisitor.Instance.Visit(outerKeySelector); innerKeySelector = JoinKeyDenullifyingExpressionVisitor.Instance.Visit(innerKeySelector); } var elements = new EnumerableRelationalQueryExpression( groupedRelationalQueryExpression.SelectExpression .AddToPredicate( Expression.Equal( outerKeySelector, innerKeySelector))); return(ExpandGroup(visited, groupedRelationalQueryExpression.OuterKeySelector, elements)); } default: { return(visited); } } }
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); } } }
public Expression CreateQueryExpression(Type elementType, DbContext context) { var targetType = context.Model.GetEntityTypes().SingleOrDefault(t => t.ClrType == elementType); Expression queryExpression; if (targetType.DefiningQuery != null) { queryExpression = targetType.DefiningQuery.Body; goto ApplyQueryFilters; } var rootType = targetType.RootType(); var schemaName = rootType.Relational().Schema ?? context.Model.Relational().DefaultSchema; var tableName = rootType.Relational().TableName; var table = new BaseTableExpression( schemaName, tableName, tableName.Substring(0, 1).ToLower(), rootType.ClrType); var materializer = CreateMaterializer(targetType, table); var projection = new ServerProjectionExpression(materializer); var selectExpression = new SelectExpression(projection, table); var discriminatingType = targetType; while (discriminatingType != null) { var discriminatorProperty = discriminatingType.Relational().DiscriminatorProperty; if (discriminatorProperty != null) { selectExpression = selectExpression.AddToPredicate( new SqlInExpression( MakeColumnExpression( table, discriminatorProperty), Expression.NewArrayInit( discriminatorProperty.ClrType, from t in discriminatingType.GetDerivedTypesInclusive() where !t.IsAbstract() select Expression.Constant( t.Relational().DiscriminatorValue, discriminatorProperty.ClrType)))); } discriminatingType = FindSameTabledPrincipalType(discriminatingType); } queryExpression = new EnumerableRelationalQueryExpression(selectExpression); ApplyQueryFilters: var currentType = targetType; var recast = false; while (currentType != null) { if (currentType.QueryFilter != null) { var filterBody = currentType.QueryFilter.Body; var repointer = new QueryFilterRepointingExpressionVisitor( DbContextParameter.GetInstance(context.GetType())); filterBody = repointer.Visit(filterBody); // Use a method call instead of adding to the SelectExpression // so the rewriting visitors are guaranteed to get their hands on the // filter. queryExpression = Expression.Call( queryableWhereMethodInfo.MakeGenericMethod(currentType.ClrType), queryExpression, Expression.Quote( Expression.Lambda( new QueryFilterExpression(filterBody), currentType.QueryFilter.Parameters))); recast |= currentType != targetType; } currentType = currentType.BaseType; } if (recast) { queryExpression = Expression.Call( queryableCastMethodInfo.MakeGenericMethod(targetType.ClrType), queryExpression); } return(queryExpression); }