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
- FrameDimension.cs
- ReadWriteSpinLock.cs
- MouseOverProperty.cs
- BoundColumn.cs
- Transform3D.cs
- ClientTarget.cs
- GenericTypeParameterBuilder.cs
- PrintDialog.cs
- SQLBytes.cs
- TimeManager.cs
- SqlMetaData.cs
- sqlpipe.cs
- Stack.cs
- AssemblyHash.cs
- RootContext.cs
- CompilationSection.cs
- Expr.cs
- GlyphTypeface.cs
- GroupLabel.cs
- ResourcesBuildProvider.cs
- Quack.cs
- BitmapPalette.cs
- ToolStripPanelDesigner.cs
- InitializerFacet.cs
- EntityDataSourceEntityTypeFilterConverter.cs
- QilFactory.cs
- DataDocumentXPathNavigator.cs
- ChangeProcessor.cs
- ConditionCollection.cs
- FixedSOMContainer.cs
- StrokeNodeOperations2.cs
- FocusWithinProperty.cs
- TdsEnums.cs
- StylusPoint.cs
- PermissionSet.cs
- AssociationType.cs
- X509CertificateClaimSet.cs
- HMACSHA256.cs
- AssociatedControlConverter.cs
- ThaiBuddhistCalendar.cs
- WebSysDefaultValueAttribute.cs
- Panel.cs
- RightsManagementEncryptedStream.cs
- QuaternionKeyFrameCollection.cs
- Compiler.cs
- MemberAccessException.cs
- BasePattern.cs
- Base64Encoder.cs
- SectionXmlInfo.cs
- PeerContact.cs
- UIPropertyMetadata.cs
- HostingPreferredMapPath.cs
- XmlQuerySequence.cs
- ProgressPage.cs
- HtmlTable.cs
- SmiEventSink_DeferedProcessing.cs
- MaskDescriptor.cs
- WS2007FederationHttpBinding.cs
- RenderData.cs
- SystemSounds.cs
- PackWebRequestFactory.cs
- PageRouteHandler.cs
- SystemSounds.cs
- WindowsFormsDesignerOptionService.cs
- Condition.cs
- SharedUtils.cs
- SafeSecurityHelper.cs
- OciHandle.cs
- HttpContextWrapper.cs
- XmlILAnnotation.cs
- TemplatePagerField.cs
- XPathChildIterator.cs
- Misc.cs
- remotingproxy.cs
- UserControlBuildProvider.cs
- Sql8ConformanceChecker.cs
- XmlCodeExporter.cs
- WindowsPrincipal.cs
- TreeNode.cs
- DataGridViewDataErrorEventArgs.cs
- KeyNotFoundException.cs
- CodeDirectoryCompiler.cs
- GregorianCalendarHelper.cs
- ServiceModelDictionary.cs
- ArgumentOutOfRangeException.cs
- PointLightBase.cs
- XPathChildIterator.cs
- SmtpDateTime.cs
- WeakKeyDictionary.cs
- StylesEditorDialog.cs
- CollectionViewSource.cs
- LinkLabel.cs
- ClassHandlersStore.cs
- VariantWrapper.cs
- ImageFormat.cs
- printdlgexmarshaler.cs
- SchemaObjectWriter.cs
- UniformGrid.cs
- ProjectionQueryOptionExpression.cs
- Encoder.cs