internal override ObjectQueryExecutionPlan GetExecutionPlan( MergeOption?forMergeOption) { MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption); ObjectQueryExecutionPlan queryExecutionPlan1 = this._cachedPlan; if (queryExecutionPlan1 != null) { if (queryExecutionPlan1.MergeOption == mergeOption && queryExecutionPlan1.Streaming == this.EffectiveStreamingBehavior) { return(queryExecutionPlan1); } queryExecutionPlan1 = (ObjectQueryExecutionPlan)null; } QueryCacheManager queryCacheManager = (QueryCacheManager)null; EntitySqlQueryCacheKey key = (EntitySqlQueryCacheKey)null; if (this.PlanCachingEnabled) { key = new EntitySqlQueryCacheKey(this.ObjectContext.DefaultContainerName, this._queryText, this.Parameters == null ? 0 : this.Parameters.Count, this.Parameters == null ? (string)null : this.Parameters.GetCacheKey(), this.Span == null ? (string)null : this.Span.GetCacheKey(), mergeOption, this.EffectiveStreamingBehavior, this.ElementType); queryCacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan queryExecutionPlan2 = (ObjectQueryExecutionPlan)null; if (queryCacheManager.TryCacheLookup <EntitySqlQueryCacheKey, ObjectQueryExecutionPlan>(key, out queryExecutionPlan2)) { queryExecutionPlan1 = queryExecutionPlan2; } } if (queryExecutionPlan1 == null) { queryExecutionPlan1 = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, this.Parse(), true), this.ElementType, mergeOption, this.EffectiveStreamingBehavior, this.Span, (IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> >)null, DbExpressionBuilder.AliasGenerator); if (key != null) { QueryCacheEntry inQueryCacheEntry = new QueryCacheEntry((QueryCacheKey)key, (object)queryExecutionPlan1); QueryCacheEntry outQueryCacheEntry = (QueryCacheEntry)null; if (queryCacheManager.TryLookupAndAdd(inQueryCacheEntry, out outQueryCacheEntry)) { queryExecutionPlan1 = (ObjectQueryExecutionPlan)outQueryCacheEntry.GetTarget(); } } } if (this.Parameters != null) { this.Parameters.SetReadOnly(true); } this._cachedPlan = queryExecutionPlan1; return(queryExecutionPlan1); }
internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption?forMergeOption) { // Determine the required merge option, with the following precedence: // 1. The merge option specified to Execute(MergeOption) as forMergeOption. // 2. The merge option set via ObjectQuery.MergeOption. // 3. The global default merge option. var mergeOption = EnsureMergeOption(forMergeOption, UserSpecifiedMergeOption); // If a cached plan is present, then it can be reused if it has the required merge option and streaming behavior // (since span and parameters cannot change between executions). However, if the cached // plan does not have the required merge option we proceed as if it were not present. var plan = _cachedPlan; if (plan != null) { if (plan.MergeOption == mergeOption && plan.Streaming == EffectiveStreamingBehavior) { return(plan); } else { plan = null; } } // There is no cached plan (or it was cleared), so the execution plan must be retrieved from // the global query cache (if plan caching is enabled) or rebuilt for the required merge option. QueryCacheManager cacheManager = null; EntitySqlQueryCacheKey cacheKey = null; if (PlanCachingEnabled) { // Create a new cache key that reflects the current state of the Parameters collection // and the Span object (if any), and uses the specified merge option. cacheKey = new EntitySqlQueryCacheKey( ObjectContext.DefaultContainerName, _queryText, (null == Parameters ? 0 : Parameters.Count), (null == Parameters ? null : Parameters.GetCacheKey()), (null == Span ? null : Span.GetCacheKey()), mergeOption, EffectiveStreamingBehavior, ElementType); cacheManager = ObjectContext.MetadataWorkspace.GetQueryCacheManager(); ObjectQueryExecutionPlan executionPlan = null; if (cacheManager.TryCacheLookup(cacheKey, out executionPlan)) { plan = executionPlan; } } if (plan == null) { // Either caching is not enabled or the execution plan was not found in the cache var queryExpression = Parse(); Debug.Assert(queryExpression != null, "EntitySqlQueryState.Parse returned null expression?"); var tree = DbQueryCommandTree.FromValidExpression( ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression, useDatabaseNullSemantics: true); plan = _objectQueryExecutionPlanFactory.Prepare( ObjectContext, tree, ElementType, mergeOption, EffectiveStreamingBehavior, Span, null, DbExpressionBuilder.AliasGenerator); // If caching is enabled then update the cache now. // Note: the logic is the same as in ELinqQueryState. if (cacheKey != null) { var newEntry = new QueryCacheEntry(cacheKey, plan); QueryCacheEntry foundEntry = null; if (cacheManager.TryLookupAndAdd(newEntry, out foundEntry)) { // If TryLookupAndAdd returns 'true' then the entry was already present in the cache when the attempt to add was made. // In this case the existing execution plan should be used. plan = (ObjectQueryExecutionPlan)foundEntry.GetTarget(); } } } if (Parameters != null) { Parameters.SetReadOnly(true); } // Update the cached plan with the newly retrieved/prepared plan _cachedPlan = plan; // Return the execution plan return(plan); }