Ejemplo n.º 1
0
        private static IList <string> GetMappedColumnList(ObjectQueryExecutionPlan plan)
        {
            // Get the column name position map in cspace.
            var columnNamePosMap = ELinqQueryState.GetColumnNamePositionMap(plan);

            if (columnNamePosMap == null || columnNamePosMap.Keys.Count == 0)
            {
                // Skip Generation if no Mapping Exists
                return(null);
            }

            var resultRowTypes = ELinqQueryState.GetMappedCommandReturnTypes(plan);

            if (resultRowTypes == null || !resultRowTypes.Any())
            {
                return(null);
            }

            IList <string> mappedColumnListSSpace = new List <string>();

            foreach (var mapped in columnNamePosMap)
            {
                EdmProperty property = resultRowTypes[0].Properties[mapped.Value];
                mappedColumnListSSpace.Add(property.Name);
            }

            return(mappedColumnListSSpace);
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Attempts to set the execution plan for <paramref name="newPlan"/>'s merge option and <paramref name="useCSharpNullComparisonBehavior"/> flag on 
        /// this cache entry to <paramref name="newPlan"/>. If a plan already exists for that merge option and UseCSharpNullComparisonBehavior flag, the 
        /// current value is not changed but is returned to the caller. Otherwise <paramref name="newPlan"/> is returned to the caller.
        /// </summary>
        /// <param name="newPlan">The new execution plan to add to this cache entry.</param>
        /// <param name="useCSharpNullComparisonBehavior">Flag indicating if C# behavior should be used for null comparisons.</param>
        /// <returns>The execution plan that corresponds to <paramref name="newPlan"/>'s merge option, which may be <paramref name="newPlan"/> or may be a previously added execution plan.</returns>
        internal ObjectQueryExecutionPlan SetExecutionPlan(ObjectQueryExecutionPlan newPlan, bool useCSharpNullComparisonBehavior)
        {
            Debug.Assert(newPlan != null, "New plan cannot be null");

            string planKey = GenerateLocalCacheKey(newPlan.MergeOption, useCSharpNullComparisonBehavior);
            // Get the value if it is there. If not, add it and get it.
            return (_plans.GetOrAdd(planKey, newPlan));
        }
        /// <summary>
        ///     Attempts to set the execution plan for <paramref name="newPlan" />'s merge option and
        ///     <paramref
        ///         name="useCSharpNullComparisonBehavior" />
        ///     flag on
        ///     this cache entry to <paramref name="newPlan" />. If a plan already exists for that merge option and UseCSharpNullComparisonBehavior flag, the
        ///     current value is not changed but is returned to the caller. Otherwise <paramref name="newPlan" /> is returned to the caller.
        /// </summary>
        /// <param name="newPlan"> The new execution plan to add to this cache entry. </param>
        /// <param name="useCSharpNullComparisonBehavior"> Flag indicating if C# behavior should be used for null comparisons. </param>
        /// <returns>
        ///     The execution plan that corresponds to <paramref name="newPlan" /> 's merge option, which may be
        ///     <paramref
        ///         name="newPlan" />
        ///     or may be a previously added execution plan.
        /// </returns>
        internal ObjectQueryExecutionPlan SetExecutionPlan(ObjectQueryExecutionPlan newPlan, bool useCSharpNullComparisonBehavior)
        {
            DebugCheck.NotNull(newPlan);

            var planKey = GenerateLocalCacheKey(newPlan.MergeOption, useCSharpNullComparisonBehavior);
            // Get the value if it is there. If not, add it and get it.
            return (_plans.GetOrAdd(planKey, newPlan));
        }
        /// <summary>
        ///     Attempts to set the execution plan for <paramref name="newPlan" />'s merge option and
        ///     <paramref
        ///         name="useCSharpNullComparisonBehavior" />
        ///     flag on
        ///     this cache entry to <paramref name="newPlan" />. If a plan already exists for that merge option and UseCSharpNullComparisonBehavior flag, the
        ///     current value is not changed but is returned to the caller. Otherwise <paramref name="newPlan" /> is returned to the caller.
        /// </summary>
        /// <param name="newPlan"> The new execution plan to add to this cache entry. </param>
        /// <param name="useCSharpNullComparisonBehavior"> Flag indicating if C# behavior should be used for null comparisons. </param>
        /// <returns>
        ///     The execution plan that corresponds to <paramref name="newPlan" /> 's merge option, which may be
        ///     <paramref
        ///         name="newPlan" />
        ///     or may be a previously added execution plan.
        /// </returns>
        internal ObjectQueryExecutionPlan SetExecutionPlan(ObjectQueryExecutionPlan newPlan, bool useCSharpNullComparisonBehavior)
        {
            DebugCheck.NotNull(newPlan);

            var planKey = GenerateLocalCacheKey(newPlan.MergeOption, useCSharpNullComparisonBehavior);

            // Get the value if it is there. If not, add it and get it.
            return(_plans.GetOrAdd(planKey, newPlan));
        }
        /// <summary>
        /// Attempts to set the execution plan for <paramref name="newPlan"/>'s merge option and <paramref name="useCSharpNullComparisonBehavior"/> flag on
        /// this cache entry to <paramref name="newPlan"/>. If a plan already exists for that merge option and UseCSharpNullComparisonBehavior flag, the
        /// current value is not changed but is returned to the caller. Otherwise <paramref name="newPlan"/> is returned to the caller.
        /// </summary>
        /// <param name="newPlan">The new execution plan to add to this cache entry.</param>
        /// <param name="useCSharpNullComparisonBehavior">Flag indicating if C# behavior should be used for null comparisons.</param>
        /// <returns>The execution plan that corresponds to <paramref name="newPlan"/>'s merge option, which may be <paramref name="newPlan"/> or may be a previously added execution plan.</returns>
        internal ObjectQueryExecutionPlan SetExecutionPlan(ObjectQueryExecutionPlan newPlan, bool useCSharpNullComparisonBehavior)
        {
            Debug.Assert(newPlan != null, "New plan cannot be null");

            string planKey = GenerateLocalCacheKey(newPlan.MergeOption, useCSharpNullComparisonBehavior);

            // Get the value if it is there. If not, add it and get it.
            return(_plans.GetOrAdd(planKey, newPlan));
        }
Ejemplo n.º 6
0
        private static IList <RowType> GetMappedCommandReturnTypes(ObjectQueryExecutionPlan plan)
        {
            EntityCommandDefinition command = plan.CommandDefinition as EntityCommandDefinition;

            if (command == null)
            {
                return(null);
            }

            return(command.MappedCommandReturnTypes);
        }
 internal bool TryGetResultType(out TypeUsage resultType)
 {
     using (IEnumerator <ObjectQueryExecutionPlan> enumerator = this._plans.Values.GetEnumerator())
     {
         if (enumerator.MoveNext())
         {
             ObjectQueryExecutionPlan current = enumerator.Current;
             resultType = current.ResultType;
             return(true);
         }
     }
     resultType = (TypeUsage)null;
     return(false);
 }
        public void Execute_sets_the_parameter_values_and_returns_the_result()
        {
            var entityCommandDefinitionMock = Mock.Get(EntityClient.MockHelper.CreateEntityCommandDefinition());
            entityCommandDefinitionMock.Setup(m => m.Parameters).Returns(
                new[]
                    {
                        new EntityParameter
                            {
                                ParameterName = "Par1"
                            }
                    });

            var objectContextMock = Mock.Get(Objects.MockHelper.CreateMockObjectContext<string>());
            objectContextMock.Setup(m => m.CommandTimeout).Returns(3);

            entityCommandDefinitionMock.Setup(m => m.ExecuteStoreCommands(It.IsAny<EntityCommand>(), It.IsAny<CommandBehavior>()))
                                       .Returns(
                                           (EntityCommand ec, CommandBehavior cb) =>
                                               {
                                                   Assert.Equal(1, ec.Parameters.Count);
                                                   Assert.Equal(2, ec.Parameters[0].Value);
                                                   Assert.Equal(3, ec.CommandTimeout);
                                                   Assert.Equal(new [] { objectContextMock.Object }, ec.InterceptionContext.ObjectContexts);
                                                   return Common.Internal.Materialization.MockHelper.CreateDbDataReader(
                                                       new[] { new object[] { "Bar" } });
                                               });

            var shaperFactory = new ShaperFactory<string>(
                1,
                Objects.MockHelper.CreateCoordinatorFactory(shaper => (string)shaper.Reader.GetValue(0)),
                new[] { typeof(string) }, new[] { true }, MergeOption.AppendOnly);

            var edmTypeMock = new Mock<EdmType>();
            edmTypeMock.Setup(m => m.BuiltInTypeKind).Returns(BuiltInTypeKind.SimpleType);

            var objectQueryExecutionPlan = new ObjectQueryExecutionPlan(
                entityCommandDefinitionMock.Object,
                shaperFactory, TypeUsage.Create(edmTypeMock.Object), MergeOption.AppendOnly, false, null, null);

            var objectParameterCollectionMock = new Mock<ObjectParameterCollection>(new ClrPerspective(new MetadataWorkspace()));

            objectParameterCollectionMock
                .Setup(m => m.GetEnumerator())
                .Returns(((IEnumerable<ObjectParameter>)new[] { new ObjectParameter("Par1", 2) }).GetEnumerator());

            var result = objectQueryExecutionPlan.Execute<string>(objectContextMock.Object, objectParameterCollectionMock.Object);

            Assert.Equal("Bar", result.Single());
        }
Ejemplo n.º 9
0
        private ObjectResult <T> GetResults(MergeOption?forMergeOption)
        {
            this.QueryState.ObjectContext.EnsureConnection();

            try
            {
                ObjectQueryExecutionPlan execPlan = this.QueryState.GetExecutionPlan(forMergeOption);
                return(execPlan.Execute <T>(this.QueryState.ObjectContext, this.QueryState.Parameters));
            }
            catch
            {
                this.QueryState.ObjectContext.ReleaseConnection();
                throw;
            }
        }
        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);
        }
Ejemplo n.º 11
0
        // Return the execution's column list in column position order.
        private static IDictionary <string, int> GetColumnNamePositionMap(ObjectQueryExecutionPlan plan)
        {
            EntityCommandDefinition command = plan.CommandDefinition as EntityCommandDefinition;

            if (command == null)
            {
                return(null);
            }

            var columnMap = command.CreateColumnMap(null) as SimpleCollectionColumnMap;

            if (columnMap == null)
            {
                return(null);
            }

            var element = columnMap.Element as RecordColumnMap;

            if (element == null)
            {
                return(null);
            }

            var properties = element.Properties;

            if (properties == null)
            {
                return(null);
            }

            var columnsPosNameMap = new Dictionary <string, int>();

            foreach (var property in properties)
            {
                var scalarProperty = property as ScalarColumnMap;

                if (scalarProperty == null)
                {
                    return(null);
                }

                columnsPosNameMap[scalarProperty.Name] = scalarProperty.ColumnPos;
            }

            return(columnsPosNameMap);
        }
        private void Execute_with_streaming(bool streaming)
        {
            var entityCommandDefinitionMock = Mock.Get(EntityClient.MockHelper.CreateEntityCommandDefinition());

            var objectContextMock = Mock.Get(Objects.MockHelper.CreateMockObjectContext<string>());
            objectContextMock.Setup(m => m.CommandTimeout).Returns(3);

            DbDataReader reader = null;
            entityCommandDefinitionMock.Setup(m => m.ExecuteStoreCommands(It.IsAny<EntityCommand>(), It.IsAny<CommandBehavior>()))
                                       .Returns(
                                           (EntityCommand ec, CommandBehavior cb) =>
                                               {
                                                   Assert.Equal(new[] { objectContextMock.Object }, ec.InterceptionContext.ObjectContexts);
                                                   reader = Common.Internal.Materialization.MockHelper.CreateDbDataReader(
                                                       new[] { new object[] { "Bar" } });
                                                   Assert.Equal(streaming ? CommandBehavior.Default : CommandBehavior.SequentialAccess, cb);
                                                   return reader;
                                               });

            var shaperFactory = new ShaperFactory<string>(
                1,
                Objects.MockHelper.CreateCoordinatorFactory(shaper => (string)shaper.Reader.GetValue(0)),
                new[] { typeof(string) }, new[] { true }, MergeOption.AppendOnly);

            var edmTypeMock = new Mock<EdmType>();
            edmTypeMock.Setup(m => m.BuiltInTypeKind).Returns(BuiltInTypeKind.SimpleType);

            var objectQueryExecutionPlan = new ObjectQueryExecutionPlan(
                entityCommandDefinitionMock.Object,
                shaperFactory, TypeUsage.Create(edmTypeMock.Object), MergeOption.AppendOnly, streaming, null, null);

            var objectParameterCollectionMock = new Mock<ObjectParameterCollection>(new ClrPerspective(new MetadataWorkspace()));

            objectParameterCollectionMock
                .Setup(m => m.GetEnumerator())
                .Returns(((IEnumerable<ObjectParameter>)new ObjectParameter[0]).GetEnumerator());

            objectQueryExecutionPlan.Execute<string>(objectContextMock.Object, objectParameterCollectionMock.Object);

            Assert.Equal(!streaming, reader.IsClosed);
        }
        public void ExecuteAsync_throws_OperationCanceledException_if_task_is_cancelled()
        {
            var executionPlan = new ObjectQueryExecutionPlan(null, null, null, MergeOption.AppendOnly, false, null, null);

            Assert.Throws<OperationCanceledException>(
                () => executionPlan.ExecuteAsync<object>(null, null, new CancellationToken(canceled: true))
                    .GetAwaiter().GetResult());
        }
        private void ExecuteAsync_disposes_the_reader_on_exception(bool streaming)
        {
            var entityCommandDefinitionMock = Mock.Get(EntityClient.MockHelper.CreateEntityCommandDefinition());

            var objectContextMock = Mock.Get(Objects.MockHelper.CreateMockObjectContext<string>());
            objectContextMock.Setup(m => m.CommandTimeout).Returns(3);

            DbDataReader reader = null;
            entityCommandDefinitionMock.Setup(
                m => m.ExecuteStoreCommandsAsync(
                    It.IsAny<EntityCommand>(),
                    It.IsAny<CommandBehavior>(), It.IsAny<CancellationToken>()))
                                       .Returns(
                                           (EntityCommand ec, CommandBehavior cb, CancellationToken ct) =>
                                               {
                                                   Assert.Equal(new[] { objectContextMock.Object }, ec.InterceptionContext.ObjectContexts);
                                                   reader = Common.Internal.Materialization.MockHelper.CreateDbDataReader(
                                                       new[] { new object[] { "Bar" } });
                                                   return Task.FromResult(reader);
                                               });

            var shaperFactory = new ShaperFactory<string>(
                1,
                Objects.MockHelper.CreateCoordinatorFactory(shaper => (string)shaper.Reader.GetValue(0)),
                new[] { typeof(string) }, new[] { true }, MergeOption.AppendOnly);

            var edmTypeMock = new Mock<EdmType>();
            edmTypeMock.Setup(m => m.BuiltInTypeKind).Returns(BuiltInTypeKind.CollectionType);

            var objectQueryExecutionPlan = new ObjectQueryExecutionPlan(
                entityCommandDefinitionMock.Object,
                shaperFactory, TypeUsage.Create(edmTypeMock.Object), MergeOption.AppendOnly, streaming, null, null);

            var objectParameterCollectionMock = new Mock<ObjectParameterCollection>(new ClrPerspective(new MetadataWorkspace()));

            objectParameterCollectionMock
                .Setup(m => m.GetEnumerator())
                .Returns(((IEnumerable<ObjectParameter>)new[] { new ObjectParameter("Par1", 2) }).GetEnumerator());

            Assert.Throws<InvalidCastException>(
                () =>
                ExceptionHelpers.UnwrapAggregateExceptions(
                    () => objectQueryExecutionPlan.ExecuteAsync<string>(
                        objectContextMock.Object,
                        objectParameterCollectionMock.Object, CancellationToken.None).Result));

            Assert.Equal(true, reader.IsClosed);
            var readerMock = Mock.Get(reader);
            readerMock.Verify(
                m => m.GetFieldValueAsync<object>(It.IsAny<int>(), It.IsAny<CancellationToken>()), streaming ? Times.Never() : Times.Once());
        }
        internal override ObjectQueryExecutionPlan GetExecutionPlan(
            MergeOption?forMergeOption)
        {
            ObjectQueryExecutionPlan queryExecutionPlan1 = this._cachedPlan;

            if (queryExecutionPlan1 != null)
            {
                MergeOption?mergeOption = ObjectQueryState.GetMergeOption(forMergeOption, this.UserSpecifiedMergeOption);
                if (mergeOption.HasValue && mergeOption.Value != queryExecutionPlan1.MergeOption || (this._recompileRequired() || this.ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior != this._useCSharpNullComparisonBehavior))
                {
                    queryExecutionPlan1 = (ObjectQueryExecutionPlan)null;
                }
            }
            if (queryExecutionPlan1 == null)
            {
                this._recompileRequired = (Func <bool>)null;
                this.ResetParameters();
                ExpressionConverter expressionConverter = this.CreateExpressionConverter();
                DbExpression        dbExpression        = expressionConverter.Convert();
                this._recompileRequired = expressionConverter.RecompileRequired;
                MergeOption mergeOption = ObjectQueryState.EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, expressionConverter.PropagatedMergeOption);
                this._useCSharpNullComparisonBehavior = this.ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior;
                this._linqParameters = expressionConverter.GetParameters();
                if (this._linqParameters != null && this._linqParameters.Any <Tuple <ObjectParameter, QueryParameterExpression> >())
                {
                    ObjectParameterCollection parameterCollection = this.EnsureParameters();
                    parameterCollection.SetReadOnly(false);
                    foreach (Tuple <ObjectParameter, QueryParameterExpression> linqParameter in this._linqParameters)
                    {
                        ObjectParameter objectParameter = linqParameter.Item1;
                        parameterCollection.Add(objectParameter);
                    }
                    parameterCollection.SetReadOnly(true);
                }
                QueryCacheManager queryCacheManager = (QueryCacheManager)null;
                LinqQueryCacheKey key1 = (LinqQueryCacheKey)null;
                string            key2;
                if (this.PlanCachingEnabled && !this._recompileRequired() && ExpressionKeyGen.TryGenerateKey(dbExpression, out key2))
                {
                    key1 = new LinqQueryCacheKey(key2, this.Parameters == null ? 0 : this.Parameters.Count, this.Parameters == null ? (string)null : this.Parameters.GetCacheKey(), expressionConverter.PropagatedSpan == null ? (string)null : expressionConverter.PropagatedSpan.GetCacheKey(), mergeOption, this.EffectiveStreamingBehavior, this._useCSharpNullComparisonBehavior, this.ElementType);
                    queryCacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager();
                    ObjectQueryExecutionPlan queryExecutionPlan2 = (ObjectQueryExecutionPlan)null;
                    if (queryCacheManager.TryCacheLookup <LinqQueryCacheKey, ObjectQueryExecutionPlan>(key1, out queryExecutionPlan2))
                    {
                        queryExecutionPlan1 = queryExecutionPlan2;
                    }
                }
                if (queryExecutionPlan1 == null)
                {
                    queryExecutionPlan1 = this._objectQueryExecutionPlanFactory.Prepare(this.ObjectContext, DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, dbExpression, !this._useCSharpNullComparisonBehavior), this.ElementType, mergeOption, this.EffectiveStreamingBehavior, expressionConverter.PropagatedSpan, (IEnumerable <Tuple <ObjectParameter, QueryParameterExpression> >)null, expressionConverter.AliasGenerator);
                    if (key1 != null)
                    {
                        QueryCacheEntry inQueryCacheEntry  = new QueryCacheEntry((QueryCacheKey)key1, (object)queryExecutionPlan1);
                        QueryCacheEntry outQueryCacheEntry = (QueryCacheEntry)null;
                        if (queryCacheManager.TryLookupAndAdd(inQueryCacheEntry, out outQueryCacheEntry))
                        {
                            queryExecutionPlan1 = (ObjectQueryExecutionPlan)outQueryCacheEntry.GetTarget();
                        }
                    }
                }
                this._cachedPlan = queryExecutionPlan1;
            }
            if (this._linqParameters != null)
            {
                foreach (Tuple <ObjectParameter, QueryParameterExpression> linqParameter in this._linqParameters)
                {
                    ObjectParameter          objectParameter     = linqParameter.Item1;
                    QueryParameterExpression parameterExpression = linqParameter.Item2;
                    if (parameterExpression != null)
                    {
                        objectParameter.Value = parameterExpression.EvaluateParameter((object[])null);
                    }
                }
            }
            return(queryExecutionPlan1);
        }
Ejemplo n.º 16
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);
        }
Ejemplo n.º 17
0
        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);
        }
Ejemplo n.º 18
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);
        }
Ejemplo n.º 19
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?");

            // If this query has already been prepared, its current execution plan may no longer be valid.
            var plan = _cachedPlan;

            if (plan != null)
            {
                // Was a merge option specified in the call to Execute(MergeOption) or set via ObjectQuery.MergeOption?
                var explicitMergeOption = GetMergeOption(forMergeOption, UserSpecifiedMergeOption);

                // If a merge option was explicitly specified, and it does not match the plan's merge option, then the plan is no longer valid.
                // If the context flag UseCSharpNullComparisonBehavior was modified, then the plan is no longer valid.
                if ((explicitMergeOption.HasValue &&
                     explicitMergeOption.Value != plan.MergeOption)
                    ||
                    _recompileRequired()
                    ||
                    ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior != _useCSharpNullComparisonBehavior)
                {
                    plan = null;
                }
            }

            // The plan may have been invalidated above, or this query may never have been prepared.
            if (plan == null)
            {
                // Metadata is required to generate the execution plan.
                ObjectContext.EnsureMetadata();

                // Reset internal state
                _recompileRequired = null;
                ResetParameters();

                // Translate LINQ expression to a DbExpression
                var converter       = CreateExpressionConverter();
                var queryExpression = converter.Convert();

                // This delegate tells us when a part of the expression tree has changed requiring a recompile.
                _recompileRequired = converter.RecompileRequired;

                // Determine the merge option, with the following precedence:
                // 1. A merge option was specified explicitly as the argument to Execute(MergeOption).
                // 2. The user has set the MergeOption property on the ObjectQuery instance.
                // 3. A merge option has been extracted from the 'root' query and propagated to the root of the expression tree.
                // 4. The global default merge option.
                var mergeOption = EnsureMergeOption(
                    forMergeOption,
                    UserSpecifiedMergeOption,
                    converter.PropagatedMergeOption);

                _useCSharpNullComparisonBehavior = ObjectContext.ContextOptions.UseCSharpNullComparisonBehavior;

                // If parameters were aggregated from referenced (non-LINQ) ObjectQuery instances then add them to the parameters collection
                _linqParameters = converter.GetParameters();
                if (_linqParameters != null &&
                    _linqParameters.Any())
                {
                    var currentParams = EnsureParameters();
                    currentParams.SetReadOnly(false);
                    foreach (var pair in _linqParameters)
                    {
                        // Note that it is safe to add the parameter directly only
                        // because parameters are cloned before they are added to the
                        // converter's parameter collection, or they came from this
                        // instance's parameter collection in the first place.
                        var convertedParam = pair.Item1;
                        currentParams.Add(convertedParam);
                    }
                    currentParams.SetReadOnly(true);
                }

                // Try retrieving the execution plan from the global query cache (if plan caching is enabled).
                QueryCacheManager cacheManager = null;
                LinqQueryCacheKey cacheKey     = null;
                if (PlanCachingEnabled && !_recompileRequired())
                {
                    // 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.
                    string expressionKey;
                    if (ExpressionKeyGen.TryGenerateKey(queryExpression, out expressionKey))
                    {
                        cacheKey = new LinqQueryCacheKey(
                            expressionKey,
                            (null == Parameters ? 0 : Parameters.Count),
                            (null == Parameters ? null : Parameters.GetCacheKey()),
                            (null == converter.PropagatedSpan ? null : converter.PropagatedSpan.GetCacheKey()),
                            mergeOption,
                            _useCSharpNullComparisonBehavior,
                            ElementType);

                        cacheManager = ObjectContext.MetadataWorkspace.GetQueryCacheManager();
                        ObjectQueryExecutionPlan executionPlan = null;
                        if (cacheManager.TryCacheLookup(cacheKey, out executionPlan))
                        {
                            plan = executionPlan;
                        }
                    }
                }

                // If execution plan wasn't retrieved from the cache, build a new one and cache it.
                if (plan == null)
                {
                    var tree = DbQueryCommandTree.FromValidExpression(ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression);
                    plan = _objectQueryExecutionPlanFactory.Prepare(
                        ObjectContext, tree, ElementType, mergeOption, converter.PropagatedSpan, null, converter.AliasGenerator);

                    // If caching is enabled then update the cache now.
                    // Note: the logic is the same as in EntitySqlQueryState.
                    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();
                        }
                    }
                }

                // Remember the current plan in the local cache, so that we don't have to recalc the key and look into the global cache
                // if the same instance of query gets executed more than once.
                _cachedPlan = plan;
            }

            // Evaluate parameter values for the query.
            if (_linqParameters != null)
            {
                foreach (var pair in _linqParameters)
                {
                    var parameter           = pair.Item1;
                    var parameterExpression = pair.Item2;
                    if (null != parameterExpression)
                    {
                        parameter.Value = parameterExpression.EvaluateParameter(null);
                    }
                }
            }

            return(plan);
        }
 internal ObjectQueryExecutionPlan SetExecutionPlan(
     ObjectQueryExecutionPlan newPlan,
     bool useCSharpNullComparisonBehavior)
 {
     return(this._plans.GetOrAdd(CompiledQueryCacheEntry.GenerateLocalCacheKey(newPlan.MergeOption, useCSharpNullComparisonBehavior), newPlan));
 }