/// <summary> /// Constructs a new ObjectSpanRewriter that will attempt to apply spanning to the specified query /// (represented as a DbExpression) when <see cref="RewriteQuery" /> is called. /// </summary> /// <param name="toRewrite"> A <see cref="DbExpression" /> representing the query to span. </param> internal ObjectSpanRewriter(DbCommandTree tree, DbExpression toRewrite, AliasGenerator aliasGenerator) { Debug.Assert(toRewrite != null, "Expression to rewrite cannot be null"); _toRewrite = toRewrite; _tree = tree; _aliasGenerator = aliasGenerator; }
/// <summary> /// Constructs a new ObjectSpanRewriter that will attempt to apply spanning to the specified query /// (represented as a DbExpression) when <see cref="RewriteQuery" /> is called. /// </summary> /// <param name="toRewrite"> /// A <see cref="DbExpression" /> representing the query to span. /// </param> internal ObjectSpanRewriter(DbCommandTree tree, DbExpression toRewrite, AliasGenerator aliasGenerator) { DebugCheck.NotNull(toRewrite); _toRewrite = toRewrite; _tree = tree; _aliasGenerator = aliasGenerator; }
public virtual ObjectQueryExecutionPlan Prepare( ObjectContext context, DbQueryCommandTree tree, Type elementType, MergeOption mergeOption, bool streaming, Span span, IEnumerable<Tuple<ObjectParameter, QueryParameterExpression>> compiledQueryParameters, AliasGenerator aliasGenerator) { var treeResultType = tree.Query.ResultType; // Rewrite this tree for Span? DbExpression spannedQuery; SpanIndex spanInfo; if (ObjectSpanRewriter.TryRewrite(tree, span, mergeOption, aliasGenerator, out spannedQuery, out spanInfo)) { tree = DbQueryCommandTree.FromValidExpression( tree.MetadataWorkspace, tree.DataSpace, spannedQuery, tree.UseDatabaseNullSemantics); } else { spanInfo = null; } var entityDefinition = CreateCommandDefinition(context, tree); var shaperFactory = Translator.TranslateColumnMap( _translator, elementType, entityDefinition.CreateColumnMap(null), context.MetadataWorkspace, spanInfo, mergeOption, streaming, false); // attempt to determine entity information for this query (e.g. which entity type and which entity set) EntitySet singleEntitySet = null; // determine if the entity set is unambiguous given the entity type if (treeResultType.EdmType.BuiltInTypeKind == BuiltInTypeKind.CollectionType && entityDefinition.EntitySets != null) { foreach (var entitySet in entityDefinition.EntitySets) { if (entitySet != null && entitySet.ElementType.IsAssignableFrom(((CollectionType)treeResultType.EdmType).TypeUsage.EdmType)) { if (singleEntitySet == null) { // found a single match singleEntitySet = entitySet; } else { // there's more than one matching entity set singleEntitySet = null; break; } } } } return new ObjectQueryExecutionPlan( entityDefinition, shaperFactory, treeResultType, mergeOption, streaming, singleEntitySet, compiledQueryParameters); }
internal static bool TryRewrite( DbQueryCommandTree tree, Span span, MergeOption mergeOption, AliasGenerator aliasGenerator, out DbExpression newQuery, out SpanIndex spanInfo) { newQuery = null; spanInfo = null; ObjectSpanRewriter rewriter = null; var requiresRelationshipSpan = Span.RequiresRelationshipSpan(mergeOption); // Potentially perform a rewrite for span. // Note that the public 'Span' property is NOT used to retrieve the Span instance // since this forces creation of a Span object that may not be required. if (span != null && span.SpanList.Count > 0) { rewriter = new ObjectFullSpanRewriter(tree, tree.Query, span, aliasGenerator); } else if (requiresRelationshipSpan) { rewriter = new ObjectSpanRewriter(tree, tree.Query, aliasGenerator); } if (rewriter != null) { rewriter.RelationshipSpan = requiresRelationshipSpan; newQuery = rewriter.RewriteQuery(); if (newQuery != null) { Debug.Assert( rewriter.SpanIndex != null || tree.Query.ResultType.EdmEquals(newQuery.ResultType), "Query was rewritten for Span but no SpanIndex was created?"); spanInfo = rewriter.SpanIndex; } } return (spanInfo != null); }
internal ObjectFullSpanRewriter(DbCommandTree tree, DbExpression toRewrite, Span span, AliasGenerator aliasGenerator) : base(tree, toRewrite, aliasGenerator) { Debug.Assert(span != null, "Span cannot be null"); Debug.Assert(span.SpanList.Count > 0, "At least one span path is required"); // Retrieve the effective 'T' of the ObjectQuery<T> that produced // the Command Tree that is being rewritten. This could be either // literally 'T' or Collection<T>. EntityType entityType = null; if (!TryGetEntityType(Query.ResultType, out entityType)) { // If the result type of the query is neither an Entity type nor a collection // type with an Entity element type, then full Span is currently not allowed. throw new InvalidOperationException(Strings.ObjectQuery_Span_IncludeRequiresEntityOrEntityCollection); } // Construct the SpanPathInfo navigation property tree using the // list of Include Span paths from the Span object: // Create a SpanPathInfo instance that represents the root of the tree // and takes its Entity type from the Entity type of the result type of the query. var spanRoot = new SpanPathInfo(entityType); // Populate the tree of navigation properties based on the navigation property names // in the Span paths from the Span object. Commonly rooted span paths are merged, so // that paths of "Customer.Order" and "Customer.Address", for example, will share a // common SpanPathInfo for "Customer" in the Children collection of the root SpanPathInfo, // and that SpanPathInfo will contain one child for "Order" and another for "Address". foreach (var path in span.SpanList) { AddSpanPath(spanRoot, path.Navigations); } // The 'current' span path is initialized to the root of the Include span tree _currentSpanPath.Push(spanRoot); }
internal OrderByLifter(AliasGenerator aliasGenerator) { _aliasGenerator = aliasGenerator; }
internal SortLifter(DbSortExpression sort, AliasGenerator aliasGenerator) : base(sort, aliasGenerator) { _sort = sort; _source = sort.Input.Expression; }
internal static DbExpression FindNavigationExpression( DbExpression expression, AliasGenerator aliasGenerator, out NavigationInfo navInfo) { Debug.Assert(TypeSemantics.IsCollectionType(expression.ResultType), "Non-collection input to projection?"); navInfo = null; var elementType = ((CollectionType)expression.ResultType.EdmType).TypeUsage; if (!TypeSemantics.IsEntityType(elementType) && !TypeSemantics.IsReferenceType(elementType)) { return expression; } var visitor = new RelationshipNavigationVisitor(aliasGenerator); var rewrittenExpression = visitor.Find(expression); if (!ReferenceEquals(expression, rewrittenExpression)) { Debug.Assert( visitor._original != null && visitor._rewritten != null, "Expression was rewritten but no navigation was found?"); navInfo = new NavigationInfo(visitor._original, visitor._rewritten); return rewrittenExpression; } else { return expression; } }
private RelationshipNavigationVisitor(AliasGenerator aliasGenerator) { _aliasGenerator = aliasGenerator; }
// <summary> // Returns a lifter instance which supports lifting the intrinsic order of the given // source expression across specific operations (filter, project, oftype, skip, and limit) // </summary> // <remarks> // Lifting only occurs for expressions that are ordered. Each of the nested // OrderByLifterBase class implementations represents one or two of the ordered patterns with // the exception of the PassthroughOrderByLifter. The latter class represents expressions // without intrinsic order that therefore require no lifting. // </remarks> internal static OrderByLifterBase GetLifter(DbExpression source, AliasGenerator aliasGenerator) { if (source.ExpressionKind == DbExpressionKind.Sort) { return new SortLifter((DbSortExpression)source, aliasGenerator); } if (source.ExpressionKind == DbExpressionKind.Project) { var project = (DbProjectExpression)source; var projectInput = project.Input.Expression; if (projectInput.ExpressionKind == DbExpressionKind.Sort) { return new ProjectSortLifter(project, (DbSortExpression)projectInput, aliasGenerator); } if (projectInput.ExpressionKind == DbExpressionKind.Skip) { return new ProjectSkipLifter(project, (DbSkipExpression)projectInput, aliasGenerator); } if (projectInput.ExpressionKind == DbExpressionKind.Limit) { var limit = (DbLimitExpression)projectInput; var limitInput = limit.Argument; if (limitInput.ExpressionKind == DbExpressionKind.Sort) { return new ProjectLimitSortLifter(project, limit, (DbSortExpression)limitInput, aliasGenerator); } if (limitInput.ExpressionKind == DbExpressionKind.Skip) { return new ProjectLimitSkipLifter(project, limit, (DbSkipExpression)limitInput, aliasGenerator); } } } if (source.ExpressionKind == DbExpressionKind.Skip) { return new SkipLifter((DbSkipExpression)source, aliasGenerator); } if (source.ExpressionKind == DbExpressionKind.Limit) { var limit = (DbLimitExpression)source; var limitInput = limit.Argument; if (limitInput.ExpressionKind == DbExpressionKind.Sort) { return new LimitSortLifter(limit, (DbSortExpression)limitInput, aliasGenerator); } if (limitInput.ExpressionKind == DbExpressionKind.Skip) { return new LimitSkipLifter(limit, (DbSkipExpression)limitInput, aliasGenerator); } if (limitInput.ExpressionKind == DbExpressionKind.Project) { var project = (DbProjectExpression)limitInput; var projectInput = project.Input.Expression; if (projectInput.ExpressionKind == DbExpressionKind.Sort) { // source.Sort(o).Project(p).Limit(k).* is equivalent to transformation for // source.Sort(o).Limit(k).Project(p).* return new ProjectLimitSortLifter(project, limit, (DbSortExpression)projectInput, aliasGenerator); } if (projectInput.ExpressionKind == DbExpressionKind.Skip) { // source.Skip(k, o).Project(p).Limit(k2).* is equivalent to transformation for // source.Skip(k, o).Limit(k2).Project(p).* return new ProjectLimitSkipLifter(project, limit, (DbSkipExpression)projectInput, aliasGenerator); } } } return new PassthroughOrderByLifter(source, aliasGenerator); }
internal LimitSkipLifter(DbLimitExpression limit, DbSkipExpression skip, AliasGenerator aliasGenerator) : base(limit, aliasGenerator) { _limit = limit; _skip = skip; }
protected OrderByLifterBase(DbExpression root, AliasGenerator aliasGenerator) { _root = root; _aliasGenerator = aliasGenerator; }
internal PassthroughOrderByLifter(DbExpression source, AliasGenerator aliasGenerator) : base(source, aliasGenerator) { }
internal LimitSortLifter(DbLimitExpression limit, DbSortExpression sort, AliasGenerator aliasGenerator) : base(limit, aliasGenerator) { _limit = limit; _sort = sort; }
internal ProjectSortLifter(DbProjectExpression project, DbSortExpression sort, AliasGenerator aliasGenerator) : base(project, aliasGenerator) { _project = project; _sort = sort; _source = sort.Input.Expression; }
internal SkipLifter(DbSkipExpression skip, AliasGenerator aliasGenerator) : base(skip, aliasGenerator) { _skip = skip; _source = skip.Input.Expression; }
internal ProjectSkipLifter(DbProjectExpression project, DbSkipExpression skip, AliasGenerator aliasGenerator) : base(project, aliasGenerator) { _project = project; _skip = skip; _source = _skip.Input.Expression; }
internal ProjectLimitSortLifter( DbProjectExpression project, DbLimitExpression limit, DbSortExpression sort, AliasGenerator aliasGenerator) : base(project, aliasGenerator) { _project = project; _limit = limit; _sort = sort; }