コード例 #1
0
 /// <summary>
 ///     Initializes a new instance of the <see cref="RelationalCompiledQueryCacheKey" /> class.
 /// </summary>
 /// <param name="compiledQueryCacheKey">The non-relational cache key.</param>
 /// <param name="useRelationalNulls">True to use relational null logic.</param>
 /// <param name="querySplittingBehavior"><see cref="QuerySplittingBehavior" /> to use when loading related collections.</param>
 /// <param name="shouldBuffer"><see langword="true" /> if the query should be buffered.</param>
 public RelationalCompiledQueryCacheKey(
     CompiledQueryCacheKey compiledQueryCacheKey,
     bool useRelationalNulls,
     QuerySplittingBehavior?querySplittingBehavior,
     bool shouldBuffer)
 {
     _compiledQueryCacheKey  = compiledQueryCacheKey;
     _useRelationalNulls     = useRelationalNulls;
     _querySplittingBehavior = querySplittingBehavior;
     _shouldBuffer           = shouldBuffer;
 }
コード例 #2
0
        internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption?forMergeOption)
        {
            Debug.Assert(Span == null, "Include span specified on compiled LINQ-based ObjectQuery instead of within the expression tree?");
            Debug.Assert(_cachedPlan == null, "Cached plan should not be set on compiled LINQ queries");

            ObjectQueryExecutionPlan plan = null;
            var cacheEntry = _cacheEntry;
            var useCSharpNullComparisonBehavior = ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior;
            var disableFilterOverProjectionSimplificationForCustomFunctions = ObjectContext.ContextOptions.DisableFilterOverProjectionSimplificationForCustomFunctions;

            if (cacheEntry != null)
            {
                // The cache entry has already been retrieved, so compute the effective merge option with the following precedence:
                // 1. The merge option specified as the argument to Execute(MergeOption), and so to this method
                // 2. The merge option set using ObjectQuery.MergeOption
                // 3. The propagated merge option as recorded in the cache entry
                // 4. The global default merge option.
                var mergeOption = EnsureMergeOption(forMergeOption, UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption);

                // Ask for the corresponding execution plan
                plan = cacheEntry.GetExecutionPlan(mergeOption, useCSharpNullComparisonBehavior);
                if (plan == null)
                {
                    // Convert the LINQ expression to produce a command tree
                    var converter       = CreateExpressionConverter();
                    var queryExpression = converter.Convert();
                    var parameters      = converter.GetParameters();

                    // Prepare the execution plan using the command tree and the computed effective merge option
                    var tree = DbQueryCommandTree.FromValidExpression(
                        ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression, !useCSharpNullComparisonBehavior, disableFilterOverProjectionSimplificationForCustomFunctions);
                    plan = _objectQueryExecutionPlanFactory.Prepare(
                        ObjectContext, tree, ElementType, mergeOption, EffectiveStreamingBehavior, converter.PropagatedSpan, parameters,
                        converter.AliasGenerator);

                    // Update and retrieve the execution plan
                    plan = cacheEntry.SetExecutionPlan(plan, useCSharpNullComparisonBehavior);
                }
            }
            else
            {
                // This instance does not yet have a reference to a cache entry.
                // First, attempt to retrieve an existing cache entry.
                var cacheManager = ObjectContext.MetadataWorkspace.GetQueryCacheManager();
                var cacheKey     = new CompiledQueryCacheKey(_cacheToken);

                if (cacheManager.TryCacheLookup(cacheKey, out cacheEntry))
                {
                    // An entry was found in the cache, so compute the effective merge option based on its propagated merge option,
                    // and use the UseCSharpNullComparisonBehavior flag to retrieve the corresponding execution plan.
                    _cacheEntry = cacheEntry;
                    var mergeOption = EnsureMergeOption(forMergeOption, UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption);
                    plan = cacheEntry.GetExecutionPlan(mergeOption, useCSharpNullComparisonBehavior);
                }

                // If no cache entry was found or if the cache entry did not contain the required execution plan, the plan is still null at this point.
                if (plan == null)
                {
                    // The execution plan needs to be produced, so create an appropriate expression converter and generate the query command tree.
                    var converter       = CreateExpressionConverter();
                    var queryExpression = converter.Convert();
                    var parameters      = converter.GetParameters();
                    var tree            = DbQueryCommandTree.FromValidExpression(
                        ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression, !useCSharpNullComparisonBehavior, disableFilterOverProjectionSimplificationForCustomFunctions);

                    // If a cache entry for this compiled query's cache key was not successfully retrieved, then it must be created now.
                    // Note that this is only possible after converting the LINQ expression and discovering the propagated merge option,
                    // which is required in order to create the cache entry.
                    if (cacheEntry == null)
                    {
                        // Create the cache entry using this instance's cache token and the propagated merge option (which may be null)
                        cacheEntry = new CompiledQueryCacheEntry(cacheKey, converter.PropagatedMergeOption);

                        // Attempt to add the entry to the cache. If an entry was added in the meantime, use that entry instead.
                        QueryCacheEntry foundEntry;
                        if (cacheManager.TryLookupAndAdd(cacheEntry, out foundEntry))
                        {
                            cacheEntry = (CompiledQueryCacheEntry)foundEntry;
                        }

                        // We now have a cache entry, so hold onto it for future use.
                        _cacheEntry = cacheEntry;
                    }

                    // Recompute the effective merge option in case a cache entry was just constructed above
                    var mergeOption = EnsureMergeOption(forMergeOption, UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption);

                    // Ask the (retrieved or constructed) cache entry for the corresponding execution plan.
                    plan = cacheEntry.GetExecutionPlan(mergeOption, useCSharpNullComparisonBehavior);
                    if (plan == null)
                    {
                        // The plan is not present, so prepare it now using the computed effective merge option
                        plan = _objectQueryExecutionPlanFactory.Prepare(
                            ObjectContext, tree, ElementType, mergeOption, EffectiveStreamingBehavior, converter.PropagatedSpan, parameters,
                            converter.AliasGenerator);

                        // Update the execution plan on the cache entry.
                        // If the execution plan was set in the meantime, SetExecutionPlan will return that value, otherwise it will return 'plan'.
                        plan = cacheEntry.SetExecutionPlan(plan, useCSharpNullComparisonBehavior);
                    }
                }
            }

            // Get parameters from the plan and set them.
            var currentParams = EnsureParameters();

            if (plan.CompiledQueryParameters != null &&
                plan.CompiledQueryParameters.Any())
            {
                currentParams.SetReadOnly(false);
                currentParams.Clear();
                foreach (var pair in plan.CompiledQueryParameters)
                {
                    // Parameters retrieved from the CompiledQueryParameters collection must be cloned before being added to the query.
                    // The cached plan is shared and when used in multithreaded scenarios failing to clone the parameter would result
                    // in the code below updating the values of shared parameter instances saved in the cached plan and used by all
                    // queries using that plan, regardless of the values they were actually invoked with, causing incorrect results
                    // when those queries were later executed.
                    //
                    var convertedParam      = pair.Item1.ShallowCopy();
                    var parameterExpression = pair.Item2;
                    currentParams.Add(convertedParam);
                    if (parameterExpression != null)
                    {
                        convertedParam.Value = parameterExpression.EvaluateParameter(_parameterValues);
                    }
                }
            }
            currentParams.SetReadOnly(true);

            Debug.Assert(plan != null, "Failed to produce an execution plan?");
            return(plan);
        }
 public RelationalCompiledQueryCacheKey(
     CompiledQueryCacheKey compiledQueryCacheKey, bool useRelationalNulls)
 {
     _compiledQueryCacheKey = compiledQueryCacheKey;
     _useRelationalNulls    = useRelationalNulls;
 }
コード例 #4
0
 private bool Equals(CompiledQueryCacheKey other)
     => string.Equals(_query, other._query)
        && _model.Equals(other._model)
        && _queryTrackingBehavior == other._queryTrackingBehavior
        && _async == other._async;
コード例 #5
0
 private bool Equals(CompiledQueryCacheKey other)
 => string.Equals(_query, other._query) &&
 _model.Equals(other._model) &&
 _queryTrackingBehavior == other._queryTrackingBehavior &&
 _async == other._async;
 public RelationalCompiledQueryCacheKey(
     CompiledQueryCacheKey compiledQueryCacheKey, bool useRelationalNulls)
 {
     _compiledQueryCacheKey = compiledQueryCacheKey;
     _useRelationalNulls = useRelationalNulls;
 }
コード例 #7
0
        internal override ObjectQueryExecutionPlan GetExecutionPlan(
            MergeOption?forMergeOption)
        {
            ObjectQueryExecutionPlan queryExecutionPlan      = (ObjectQueryExecutionPlan)null;
            CompiledQueryCacheEntry  compiledQueryCacheEntry = this._cacheEntry;
            bool comparisonBehavior = this.ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior;

            if (compiledQueryCacheEntry != null)
            {
                MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, compiledQueryCacheEntry.PropagatedMergeOption);
                queryExecutionPlan = compiledQueryCacheEntry.GetExecutionPlan(mergeOption, comparisonBehavior);
                if (queryExecutionPlan == null)
                {
                    ExpressionConverter expressionConverter = this.CreateExpressionConverter();
                    DbExpression        query = expressionConverter.Convert();
                    IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> > parameters = expressionConverter.GetParameters();
                    ObjectQueryExecutionPlan newPlan = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, query, !comparisonBehavior), this.ElementType, mergeOption, this.EffectiveStreamingBehavior, expressionConverter.PropagatedSpan, parameters, expressionConverter.AliasGenerator);
                    queryExecutionPlan = compiledQueryCacheEntry.SetExecutionPlan(newPlan, comparisonBehavior);
                }
            }
            else
            {
                QueryCacheManager     queryCacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager();
                CompiledQueryCacheKey key = new CompiledQueryCacheKey(this._cacheToken);
                if (queryCacheManager.TryCacheLookup <CompiledQueryCacheKey, CompiledQueryCacheEntry>(key, out compiledQueryCacheEntry))
                {
                    this._cacheEntry = compiledQueryCacheEntry;
                    MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, compiledQueryCacheEntry.PropagatedMergeOption);
                    queryExecutionPlan = compiledQueryCacheEntry.GetExecutionPlan(mergeOption, comparisonBehavior);
                }
                if (queryExecutionPlan == null)
                {
                    ExpressionConverter expressionConverter = this.CreateExpressionConverter();
                    DbExpression        query = expressionConverter.Convert();
                    IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> > parameters = expressionConverter.GetParameters();
                    DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, query, !comparisonBehavior);
                    if (compiledQueryCacheEntry == null)
                    {
                        compiledQueryCacheEntry = new CompiledQueryCacheEntry((QueryCacheKey)key, expressionConverter.PropagatedMergeOption);
                        QueryCacheEntry outQueryCacheEntry;
                        if (queryCacheManager.TryLookupAndAdd((QueryCacheEntry)compiledQueryCacheEntry, out outQueryCacheEntry))
                        {
                            compiledQueryCacheEntry = (CompiledQueryCacheEntry)outQueryCacheEntry;
                        }
                        this._cacheEntry = compiledQueryCacheEntry;
                    }
                    MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, compiledQueryCacheEntry.PropagatedMergeOption);
                    queryExecutionPlan = compiledQueryCacheEntry.GetExecutionPlan(mergeOption, comparisonBehavior);
                    if (queryExecutionPlan == null)
                    {
                        ObjectQueryExecutionPlan newPlan = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, this.EffectiveStreamingBehavior, expressionConverter.PropagatedSpan, parameters, expressionConverter.AliasGenerator);
                        queryExecutionPlan = compiledQueryCacheEntry.SetExecutionPlan(newPlan, comparisonBehavior);
                    }
                }
            }
            ObjectParameterCollection parameterCollection = this.EnsureParameters();

            if (queryExecutionPlan.CompiledQueryParameters != null && queryExecutionPlan.CompiledQueryParameters.Any <Tuple <ObjectParameter, QueryParameterExpression> >())
            {
                parameterCollection.SetReadOnly(false);
                parameterCollection.Clear();
                foreach (Tuple <ObjectParameter, QueryParameterExpression> compiledQueryParameter in queryExecutionPlan.CompiledQueryParameters)
                {
                    ObjectParameter          objectParameter     = compiledQueryParameter.Item1.ShallowCopy();
                    QueryParameterExpression parameterExpression = compiledQueryParameter.Item2;
                    parameterCollection.Add(objectParameter);
                    if (parameterExpression != null)
                    {
                        objectParameter.Value = parameterExpression.EvaluateParameter(this._parameterValues);
                    }
                }
            }
            parameterCollection.SetReadOnly(true);
            return(queryExecutionPlan);
        }