Code:
/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / CompiledELinqQueryState.cs / 1599186 / CompiledELinqQueryState.cs
//---------------------------------------------------------------------- //// Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- namespace System.Data.Objects.ELinq { using System; using System.Collections.Generic; using System.Data.Common.CommandTrees; using System.Data.Objects; using System.Data.Objects.ELinq; using System.Data.Objects.Internal; using System.Diagnostics; using System.Linq; using System.Data.Metadata.Edm; using System.Linq.Expressions; using System.Data.Entity; using System.Reflection; using System.Data.Common.QueryCache; using System.Data.Common.CommandTrees.ExpressionBuilder; using System.Collections.ObjectModel; ////// Models a compiled Linq to Entities ObjectQuery /// internal sealed class CompiledELinqQueryState : ELinqQueryState { private readonly Guid _cacheToken; private readonly object[] _parameterValues; private CompiledQueryCacheEntry _cacheEntry; ////// Factory method to create a new compiled query state instance /// /// The element type of the new instance (the 'T' of the ObjectQuery<T> that the new state instance will back)" /// The object context with which the new instance should be associated /// The compiled query definition, as a/// The cache token to use when retrieving or storing the new instance's execution plan in the query cache /// The values passed into the CompiledQuery delegate internal CompiledELinqQueryState(Type elementType, ObjectContext context, LambdaExpression lambda, Guid cacheToken, object[] parameterValues) : base(elementType, context, lambda) { EntityUtil.CheckArgumentNull(parameterValues, "parameterValues"); _cacheToken = cacheToken; _parameterValues = parameterValues; this.EnsureParameters(); this.Parameters.SetReadOnly(true); } internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption? forMergeOption) { Debug.Assert(this.Span == null, "Include span specified on compiled LINQ-based ObjectQuery instead of within the expression tree?"); Debug.Assert(this._cachedPlan == null, "Cached plan should not be set on compiled LINQ queries"); // Metadata is required to generate the execution plan or to retrieve it from the cache. this.ObjectContext.EnsureMetadata(); ObjectQueryExecutionPlan plan = null; CompiledQueryCacheEntry cacheEntry = this._cacheEntry; 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. MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); // Ask for the corresponding execution plan plan = cacheEntry.GetExecutionPlan(mergeOption); if (plan == null) { // Convert the LINQ expression to produce a command tree ExpressionConverter converter = this.CreateExpressionConverter(); DbExpression queryExpression = converter.Convert(); ReadOnlyCollection > parameters = converter.GetParameters(); // Prepare the execution plan using the command tree and the computed effective merge option DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression); plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan, parameters); // Update and retrieve the execution plan plan = cacheEntry.SetExecutionPlan(plan); } } else { // This instance does not yet have a reference to a cache entry. // First, attempt to retrieve an existing cache entry. QueryCacheManager cacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); CompiledQueryCacheKey cacheKey = new CompiledQueryCacheKey(this._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 attempt to retrieve the corresponding execution plan. this._cacheEntry = cacheEntry; MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); plan = cacheEntry.GetExecutionPlan(mergeOption); } // 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. ExpressionConverter converter = this.CreateExpressionConverter(); DbExpression queryExpression = converter.Convert(); ReadOnlyCollection > parameters = converter.GetParameters(); DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression); // 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. this._cacheEntry = cacheEntry; } // Recompute the effective merge option in case a cache entry was just constructed above MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); // Ask the (retrieved or constructed) cache entry for the corresponding execution plan. plan = cacheEntry.GetExecutionPlan(mergeOption); if (plan == null) { // The plan is not present, so prepare it now using the computed effective merge option plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan, parameters); // Update the execution plan for the merge option 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); } } } // Get parameters from the plan and set them. ObjectParameterCollection currentParams = this.EnsureParameters(); if (plan.CompiledQueryParameters != null && plan.CompiledQueryParameters.Count > 0) { currentParams.SetReadOnly(false); currentParams.Clear(); foreach (KeyValuePair 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. // ObjectParameter convertedParam = pair.Key.ShallowCopy(); QueryParameterExpression parameterExpression = pair.Value; 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; } /// /// Overrides GetResultType and attempts to first retrieve the result type from the cache entry. /// ///The query result type from this compiled query's cache entry, if possible; otherwise defers to protected override TypeUsage GetResultType() { CompiledQueryCacheEntry cacheEntry = this._cacheEntry; TypeUsage resultType; if (cacheEntry != null && cacheEntry.TryGetResultType(out resultType)) { return resultType; } return base.GetResultType(); } ////// Gets a LINQ expression that defines this query. /// This is overridden to remove parameter references from the underlying expression, /// producing an expression that contains the values of those parameters as internal override Expression Expression { get { return CreateDonateableExpressionVisitor.Replace((LambdaExpression)base.Expression, ObjectContext, _parameterValues); } } ///s. /// /// Overrides CreateExpressionConverter to return a converter that uses a binding context based on the compiled query parameters, /// rather than a default binding context. /// ///An expression converter appropriate for converting this compiled query state instance protected override ExpressionConverter CreateExpressionConverter() { LambdaExpression lambda = (LambdaExpression)base.Expression; Funcletizer funcletizer = Funcletizer.CreateCompiledQueryEvaluationFuncletizer(this.ObjectContext, lambda.Parameters.First(), lambda.Parameters.Skip(1).ToList().AsReadOnly()); // Return a new expression converter that uses the initialized command tree and binding context. return new ExpressionConverter(funcletizer, lambda.Body); } ////// Replaces ParameterExpresion with ConstantExpression /// to make the expression usable as a donor expression /// private sealed class CreateDonateableExpressionVisitor : EntityExpressionVisitor { private readonly Dictionary_parameterToValueLookup; private CreateDonateableExpressionVisitor(Dictionary parameterToValueLookup) { _parameterToValueLookup = parameterToValueLookup; } internal static Expression Replace(LambdaExpression query, ObjectContext objectContext, object[] parameterValues) { Dictionary parameterLookup = query .Parameters .Skip(1) .Zip(parameterValues) .ToDictionary(pair => pair.Key, pair => pair.Value); parameterLookup.Add(query.Parameters.First(), objectContext); var replacer = new CreateDonateableExpressionVisitor(parameterLookup); return replacer.Visit(query.Body); } internal override Expression VisitParameter(ParameterExpression p) { object value; Expression result; if (_parameterToValueLookup.TryGetValue(p, out value)) { result = Expression.Constant(value, p.Type); } else { result = base.VisitParameter(p); } return result; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //---------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- namespace System.Data.Objects.ELinq { using System; using System.Collections.Generic; using System.Data.Common.CommandTrees; using System.Data.Objects; using System.Data.Objects.ELinq; using System.Data.Objects.Internal; using System.Diagnostics; using System.Linq; using System.Data.Metadata.Edm; using System.Linq.Expressions; using System.Data.Entity; using System.Reflection; using System.Data.Common.QueryCache; using System.Data.Common.CommandTrees.ExpressionBuilder; using System.Collections.ObjectModel; ////// Models a compiled Linq to Entities ObjectQuery /// internal sealed class CompiledELinqQueryState : ELinqQueryState { private readonly Guid _cacheToken; private readonly object[] _parameterValues; private CompiledQueryCacheEntry _cacheEntry; ////// Factory method to create a new compiled query state instance /// /// The element type of the new instance (the 'T' of the ObjectQuery<T> that the new state instance will back)" /// The object context with which the new instance should be associated /// The compiled query definition, as a/// The cache token to use when retrieving or storing the new instance's execution plan in the query cache /// The values passed into the CompiledQuery delegate internal CompiledELinqQueryState(Type elementType, ObjectContext context, LambdaExpression lambda, Guid cacheToken, object[] parameterValues) : base(elementType, context, lambda) { EntityUtil.CheckArgumentNull(parameterValues, "parameterValues"); _cacheToken = cacheToken; _parameterValues = parameterValues; this.EnsureParameters(); this.Parameters.SetReadOnly(true); } internal override ObjectQueryExecutionPlan GetExecutionPlan(MergeOption? forMergeOption) { Debug.Assert(this.Span == null, "Include span specified on compiled LINQ-based ObjectQuery instead of within the expression tree?"); Debug.Assert(this._cachedPlan == null, "Cached plan should not be set on compiled LINQ queries"); // Metadata is required to generate the execution plan or to retrieve it from the cache. this.ObjectContext.EnsureMetadata(); ObjectQueryExecutionPlan plan = null; CompiledQueryCacheEntry cacheEntry = this._cacheEntry; 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. MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); // Ask for the corresponding execution plan plan = cacheEntry.GetExecutionPlan(mergeOption); if (plan == null) { // Convert the LINQ expression to produce a command tree ExpressionConverter converter = this.CreateExpressionConverter(); DbExpression queryExpression = converter.Convert(); ReadOnlyCollection > parameters = converter.GetParameters(); // Prepare the execution plan using the command tree and the computed effective merge option DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression); plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan, parameters); // Update and retrieve the execution plan plan = cacheEntry.SetExecutionPlan(plan); } } else { // This instance does not yet have a reference to a cache entry. // First, attempt to retrieve an existing cache entry. QueryCacheManager cacheManager = this.ObjectContext.MetadataWorkspace.GetQueryCacheManager(); CompiledQueryCacheKey cacheKey = new CompiledQueryCacheKey(this._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 attempt to retrieve the corresponding execution plan. this._cacheEntry = cacheEntry; MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); plan = cacheEntry.GetExecutionPlan(mergeOption); } // 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. ExpressionConverter converter = this.CreateExpressionConverter(); DbExpression queryExpression = converter.Convert(); ReadOnlyCollection > parameters = converter.GetParameters(); DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression); // 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. this._cacheEntry = cacheEntry; } // Recompute the effective merge option in case a cache entry was just constructed above MergeOption mergeOption = EnsureMergeOption(forMergeOption, this.UserSpecifiedMergeOption, cacheEntry.PropagatedMergeOption); // Ask the (retrieved or constructed) cache entry for the corresponding execution plan. plan = cacheEntry.GetExecutionPlan(mergeOption); if (plan == null) { // The plan is not present, so prepare it now using the computed effective merge option plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan, parameters); // Update the execution plan for the merge option 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); } } } // Get parameters from the plan and set them. ObjectParameterCollection currentParams = this.EnsureParameters(); if (plan.CompiledQueryParameters != null && plan.CompiledQueryParameters.Count > 0) { currentParams.SetReadOnly(false); currentParams.Clear(); foreach (KeyValuePair 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. // ObjectParameter convertedParam = pair.Key.ShallowCopy(); QueryParameterExpression parameterExpression = pair.Value; 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; } /// /// Overrides GetResultType and attempts to first retrieve the result type from the cache entry. /// ///The query result type from this compiled query's cache entry, if possible; otherwise defers to protected override TypeUsage GetResultType() { CompiledQueryCacheEntry cacheEntry = this._cacheEntry; TypeUsage resultType; if (cacheEntry != null && cacheEntry.TryGetResultType(out resultType)) { return resultType; } return base.GetResultType(); } ////// Gets a LINQ expression that defines this query. /// This is overridden to remove parameter references from the underlying expression, /// producing an expression that contains the values of those parameters as internal override Expression Expression { get { return CreateDonateableExpressionVisitor.Replace((LambdaExpression)base.Expression, ObjectContext, _parameterValues); } } ///s. /// /// Overrides CreateExpressionConverter to return a converter that uses a binding context based on the compiled query parameters, /// rather than a default binding context. /// ///An expression converter appropriate for converting this compiled query state instance protected override ExpressionConverter CreateExpressionConverter() { LambdaExpression lambda = (LambdaExpression)base.Expression; Funcletizer funcletizer = Funcletizer.CreateCompiledQueryEvaluationFuncletizer(this.ObjectContext, lambda.Parameters.First(), lambda.Parameters.Skip(1).ToList().AsReadOnly()); // Return a new expression converter that uses the initialized command tree and binding context. return new ExpressionConverter(funcletizer, lambda.Body); } ////// Replaces ParameterExpresion with ConstantExpression /// to make the expression usable as a donor expression /// private sealed class CreateDonateableExpressionVisitor : EntityExpressionVisitor { private readonly Dictionary_parameterToValueLookup; private CreateDonateableExpressionVisitor(Dictionary parameterToValueLookup) { _parameterToValueLookup = parameterToValueLookup; } internal static Expression Replace(LambdaExpression query, ObjectContext objectContext, object[] parameterValues) { Dictionary parameterLookup = query .Parameters .Skip(1) .Zip(parameterValues) .ToDictionary(pair => pair.Key, pair => pair.Value); parameterLookup.Add(query.Parameters.First(), objectContext); var replacer = new CreateDonateableExpressionVisitor(parameterLookup); return replacer.Visit(query.Body); } internal override Expression VisitParameter(ParameterExpression p) { object value; Expression result; if (_parameterToValueLookup.TryGetValue(p, out value)) { result = Expression.Constant(value, p.Type); } else { result = base.VisitParameter(p); } return result; } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu
This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- DbDataRecord.cs
- AutoGeneratedField.cs
- CodeNamespaceImport.cs
- IISMapPath.cs
- InternalPermissions.cs
- ToolStripItemDataObject.cs
- hresults.cs
- BrowserCapabilitiesCodeGenerator.cs
- CodeDelegateCreateExpression.cs
- TypeSystemProvider.cs
- Model3DGroup.cs
- CmsUtils.cs
- COM2FontConverter.cs
- XmlNotation.cs
- ManifestResourceInfo.cs
- WorkflowMarkupElementEventArgs.cs
- FramingDecoders.cs
- SecurityContextSecurityTokenResolver.cs
- WinEventTracker.cs
- Lasso.cs
- _Semaphore.cs
- MinimizableAttributeTypeConverter.cs
- IssuanceLicense.cs
- EventSourceCreationData.cs
- HtmlControl.cs
- RotateTransform.cs
- DeflateEmulationStream.cs
- HttpInputStream.cs
- BevelBitmapEffect.cs
- TypedDatasetGenerator.cs
- ILGenerator.cs
- ContainerControl.cs
- DataGridPageChangedEventArgs.cs
- MetadataException.cs
- CompositeActivityDesigner.cs
- Context.cs
- WaitHandleCannotBeOpenedException.cs
- TransactionInterop.cs
- TargetControlTypeCache.cs
- RoamingStoreFile.cs
- BindingSource.cs
- SymbolMethod.cs
- PointUtil.cs
- AssemblyNameProxy.cs
- InternalBufferOverflowException.cs
- BooleanAnimationUsingKeyFrames.cs
- NavigationService.cs
- AsyncPostBackErrorEventArgs.cs
- SqlUnionizer.cs
- StylusTip.cs
- HierarchicalDataTemplate.cs
- TextTreeInsertElementUndoUnit.cs
- WebPartEventArgs.cs
- SignedInfo.cs
- CodeSnippetExpression.cs
- ReflectionHelper.cs
- ClonableStack.cs
- WebPartVerbCollection.cs
- DataTableExtensions.cs
- MetadataExchangeClient.cs
- SqlInternalConnectionSmi.cs
- WebControlsSection.cs
- WorkflowServiceAttributes.cs
- DrawingDrawingContext.cs
- OdbcEnvironmentHandle.cs
- StretchValidation.cs
- CodeAccessPermission.cs
- Line.cs
- UMPAttributes.cs
- TabControl.cs
- UIElement.cs
- OLEDB_Enum.cs
- KeyMatchBuilder.cs
- Baml2006ReaderContext.cs
- CatalogPartCollection.cs
- ModelItemCollection.cs
- ContainerSelectorActiveEvent.cs
- Sequence.cs
- IncrementalReadDecoders.cs
- ValidationError.cs
- Freezable.cs
- ClaimSet.cs
- WebBaseEventKeyComparer.cs
- AccessibilityHelperForXpWin2k3.cs
- PassportAuthentication.cs
- SerializationSectionGroup.cs
- GridLengthConverter.cs
- FreeFormDesigner.cs
- DebugView.cs
- SQLBytesStorage.cs
- OutputScopeManager.cs
- ViewStateException.cs
- ServiceReflector.cs
- MailMessageEventArgs.cs
- BrowserCapabilitiesFactoryBase.cs
- Single.cs
- AnnotationAuthorChangedEventArgs.cs
- CompareInfo.cs
- LongCountAggregationOperator.cs
- PrintPreviewControl.cs