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
- FormViewUpdatedEventArgs.cs
- isolationinterop.cs
- LeftCellWrapper.cs
- smtpconnection.cs
- SchemaElementDecl.cs
- MeshGeometry3D.cs
- MethodBuilderInstantiation.cs
- TTSEngineTypes.cs
- TextRangeProviderWrapper.cs
- DocumentSequenceHighlightLayer.cs
- WindowsListBox.cs
- DependencyPropertyAttribute.cs
- SystemNetHelpers.cs
- ServiceHttpHandlerFactory.cs
- ChtmlMobileTextWriter.cs
- ExtenderHelpers.cs
- ContentTypeSettingDispatchMessageFormatter.cs
- HandlerBase.cs
- StateBag.cs
- MobileCategoryAttribute.cs
- HttpPostedFile.cs
- MetadataArtifactLoaderCompositeResource.cs
- SmiContextFactory.cs
- RayMeshGeometry3DHitTestResult.cs
- SecurityUtils.cs
- ParentControlDesigner.cs
- ByteStack.cs
- DurableDispatcherAddressingFault.cs
- BitVector32.cs
- COSERVERINFO.cs
- RoleGroupCollection.cs
- UnauthorizedWebPart.cs
- SqlConnectionPoolGroupProviderInfo.cs
- EntityDataSourceColumn.cs
- ConstraintStruct.cs
- CompensatableSequenceActivity.cs
- DateTimeConstantAttribute.cs
- TextTreeFixupNode.cs
- _LocalDataStoreMgr.cs
- ReverseInheritProperty.cs
- CellTreeNodeVisitors.cs
- BitmapEffectGroup.cs
- WindowsSlider.cs
- GroupBoxRenderer.cs
- BindableAttribute.cs
- ScriptResourceDefinition.cs
- FormView.cs
- Bits.cs
- XmlSiteMapProvider.cs
- TextSelectionHighlightLayer.cs
- SmtpReplyReaderFactory.cs
- PropertyDescriptorCollection.cs
- XmlCharCheckingWriter.cs
- FileDetails.cs
- BitmapCodecInfoInternal.cs
- PackageDigitalSignatureManager.cs
- GridToolTip.cs
- DefaultParameterValueAttribute.cs
- BaseCollection.cs
- httpserverutility.cs
- MethodInfo.cs
- ContextMenuAutomationPeer.cs
- Light.cs
- ThumbButtonInfo.cs
- DecoderFallback.cs
- TransformGroup.cs
- WebPartMovingEventArgs.cs
- DetailsViewModeEventArgs.cs
- OperandQuery.cs
- PrePrepareMethodAttribute.cs
- ColorAnimationUsingKeyFrames.cs
- ProviderBase.cs
- DetailsViewPagerRow.cs
- TraceSection.cs
- XmlSubtreeReader.cs
- SendingRequestEventArgs.cs
- CallbackHandler.cs
- DataSpaceManager.cs
- WebException.cs
- ResourceProviderFactory.cs
- ListViewItem.cs
- DetailsViewDeletedEventArgs.cs
- XamlTypeMapper.cs
- LineUtil.cs
- WeakReferenceList.cs
- Win32Interop.cs
- IPCCacheManager.cs
- FileDialog.cs
- ListDesigner.cs
- CustomAssemblyResolver.cs
- _ConnectStream.cs
- SystemIcmpV4Statistics.cs
- SystemParameters.cs
- ToolStripLabel.cs
- Ref.cs
- FaultDescriptionCollection.cs
- QuaternionKeyFrameCollection.cs
- InfoCardRSAPKCS1KeyExchangeFormatter.cs
- SqlConnectionHelper.cs
- TimelineGroup.cs