Code:
/ Dotnetfx_Win7_3.5.1 / Dotnetfx_Win7_3.5.1 / 3.5.1 / DEVDIV / depot / DevDiv / releases / Orcas / NetFXw7 / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / CompiledELinqQueryState.cs / 1 / 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 CqtExpression = System.Data.Common.CommandTrees.DbExpression; using LinqExpression = System.Linq.Expressions.Expression; using System.Data.Metadata.Edm; using System.Linq.Expressions; using System.Data.Entity; using System.Reflection; using System.Data.Common.QueryCache; ////// Models a compiled Linq to Entities ObjectQuery /// internal sealed class CompiledELinqQueryState : ELinqQueryState { private readonly ParameterExpression _rootContextParameter; private readonly CompiledQueryParameter[] _parameters; private readonly Guid _cacheToken; 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 parameters that are available to the new compiled query state instance; correspond with the lambda parameters /// The cache token to use when retrieving or storing the new instance's execution plan in the query cache /// The new compiled query state instance internal static CompiledELinqQueryState Create(Type elementType, ObjectContext context, LambdaExpression lambda, DictionaryobjectParameters, Guid cacheToken) { EntityUtil.CheckArgumentNull(context, "context"); ObjectParameterCollection objectQueryParameters = new ObjectParameterCollection(context.Perspective); CompiledQueryParameter[] compiledParams = new CompiledQueryParameter[objectParameters.Count]; int i = 0; foreach (KeyValuePair objectParameter in objectParameters) { compiledParams[i] = new CompiledQueryParameter(objectParameter.Key, objectParameter.Value); try { objectQueryParameters.Add(compiledParams[i].ObjectParameter); } catch (ArgumentOutOfRangeException) { // If this is a simple query parameter (involving a single delegate parameter) report the // type of that parameter. Otherwise, report the type of the part of the parameter. HashSet parameters = ParameterExpressionVisitor.FindAllParametersInExpression(objectParameter.Key); Type parameterType = parameters.Count == 1 ? parameters.Single().Type : objectParameter.Value.ParameterType; throw EntityUtil.NotSupported(Strings.CompiledELinq_UnsupportedParameterType(parameterType.FullName)); } i++; } return new CompiledELinqQueryState(elementType, context, objectQueryParameters, compiledParams, lambda, cacheToken); } private CompiledELinqQueryState(Type elementType, ObjectContext context, ObjectParameterCollection objectParameters, CompiledQueryParameter[] compiledParams, LambdaExpression lambda, Guid cacheToken) : base(elementType, context, objectParameters, lambda.Body) { Debug.Assert(objectParameters != null, "A parameter collection is required"); _rootContextParameter = lambda.Parameters[0]; _parameters = compiledParams; _cacheToken = cacheToken; // The parameters available to a compiled query are fixed. this.EnsureParameters().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(); DbQueryCommandTree tree = (DbQueryCommandTree)queryExpression.CommandTree; tree.Query = queryExpression; // Prepare the execution plan using the command tree and the computed effective merge option plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan); // 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(); DbQueryCommandTree tree = (DbQueryCommandTree)queryExpression.CommandTree; tree.Query = 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); // 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); } } } 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(base.Expression, ObjectContext, _rootContextParameter, _parameters); } } ///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() { // Create the command tree used for conversion and add the fixed set of parameters to it DbQueryCommandTree tree = new DbQueryCommandTree(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace); foreach (var parameter in _parameters) { parameter.CreateParameterReferenceAndAddParameterToCommandTree(tree, this.ObjectContext.Perspective); } // Initialize a binding context based on the compiled query parameters. BindingContext context = new BindingContext(_rootContextParameter, this.ObjectContext, _parameters); // Return a new expression converter that uses the initialized command tree and binding context. return new ExpressionConverter(this.ObjectContext, context, tree, base.Expression, this.Parameters); } ////// Replaces ParameterExpresion with ConstantExpression /// to make the expression usable as a donor expression /// private sealed class CreateDonateableExpressionVisitor : ExpressionVisitor { private readonly Dictionary_parameterToValueLookup; private readonly BindingContext _bindingContext; private CreateDonateableExpressionVisitor(BindingContext bindingContext, Dictionary parameterToValueLookup) { Debug.Assert(bindingContext != null, "bindingContext must have a value"); Debug.Assert(parameterToValueLookup != null, "parameterToValueLookup must have a value"); _bindingContext = bindingContext; _parameterToValueLookup = parameterToValueLookup; } internal static Expression Replace(Expression input, ObjectContext objectContext, ParameterExpression rootContextParameter, CompiledQueryParameter [] parameters) { BindingContext bindingContext = new BindingContext(rootContextParameter, objectContext, parameters); Dictionary parameterLookup = parameters.ToDictionary(p => p.Expression, p => p.ObjectParameter.Value); var replacer = new CreateDonateableExpressionVisitor(bindingContext, parameterLookup); return replacer.Visit(input); } /// /// Replace all the known (outer scope) Expressions with ConstantExpressions /// /// The Expression to replace ///The new constant expression internal override Expression Visit(Expression expression) { object value; if (null != expression && _parameterToValueLookup.TryGetValue(expression, out value)) { return Expression.Constant(value, expression.Type); } return base.Visit(expression); } internal override Expression VisitMethodCall(MethodCallExpression m) { Expression newExpression; if (TryReplaceRootQuery(m, out newExpression)) { return newExpression; } return base.VisitMethodCall(m); } internal override Expression VisitMemberAccess(MemberExpression m) { Expression newExpression; if (TryReplaceRootQuery(m, out newExpression)) { return newExpression; } return base.VisitMemberAccess(m); } bool TryReplaceRootQuery(Expression expression, out Expression newExpression) { ObjectQuery rootQuery; if (ExpressionEvaluator.TryEvaluateRootQuery(_bindingContext, expression, out rootQuery)) { Debug.Assert(typeof(ObjectQuery).IsAssignableFrom(expression.Type), "how did we get a different type"); newExpression = Expression.Constant(rootQuery, expression.Type); return true; } newExpression = null; return false; } } ////// Collects parameters expressions from a LINQ expression tree. /// private sealed class ParameterExpressionVisitor : ExpressionVisitor { internal readonly HashSet_parameters = new HashSet (); private ParameterExpressionVisitor() { } internal static HashSet FindAllParametersInExpression(Expression expression) { ParameterExpressionVisitor visitor = new ParameterExpressionVisitor(); visitor.Visit(expression); return visitor._parameters; } internal override Expression VisitParameter(ParameterExpression p) { _parameters.Add(p); return base.VisitParameter(p); } } } internal sealed class CompiledQueryParameter { private readonly Expression _expression; private readonly ObjectParameter _parameter; private DbParameterReferenceExpression _parameterReference; internal CompiledQueryParameter(Expression expression, ObjectParameter parameter) { _expression = expression; _parameter = parameter; } /// /// Adds the ObjectParameter to the DbCommandTree, and creates a ParameterReferenceExpression /// to be placed in the proper places in the tree /// /// The command tree to create operate on. /// The ClrPerspective to help get the correct TypeUsage. internal void CreateParameterReferenceAndAddParameterToCommandTree(DbCommandTree commandTree, ClrPerspective perspective) { Debug.Assert(_parameterReference == null, "don't call this once it is already setup"); TypeUsage typeUsage; if(ClosureBinding.TryGetTypeUsageForObjectParameter(_parameter, perspective, out typeUsage)) { commandTree.AddParameter(_parameter.Name, typeUsage); _parameterReference = commandTree.CreateParameterReferenceExpression(_parameter.Name); } Debug.Assert(_parameterReference != null, "Not sure why this would ever happen, and it isn't handled"); } internal Expression Expression { get { return _expression; } } internal ObjectParameter ObjectParameter { get { return _parameter; } } internal DbParameterReferenceExpression ParameterReference { get { return _parameterReference; } } } } // 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 CqtExpression = System.Data.Common.CommandTrees.DbExpression; using LinqExpression = System.Linq.Expressions.Expression; using System.Data.Metadata.Edm; using System.Linq.Expressions; using System.Data.Entity; using System.Reflection; using System.Data.Common.QueryCache; ////// Models a compiled Linq to Entities ObjectQuery /// internal sealed class CompiledELinqQueryState : ELinqQueryState { private readonly ParameterExpression _rootContextParameter; private readonly CompiledQueryParameter[] _parameters; private readonly Guid _cacheToken; 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 parameters that are available to the new compiled query state instance; correspond with the lambda parameters /// The cache token to use when retrieving or storing the new instance's execution plan in the query cache /// The new compiled query state instance internal static CompiledELinqQueryState Create(Type elementType, ObjectContext context, LambdaExpression lambda, DictionaryobjectParameters, Guid cacheToken) { EntityUtil.CheckArgumentNull(context, "context"); ObjectParameterCollection objectQueryParameters = new ObjectParameterCollection(context.Perspective); CompiledQueryParameter[] compiledParams = new CompiledQueryParameter[objectParameters.Count]; int i = 0; foreach (KeyValuePair objectParameter in objectParameters) { compiledParams[i] = new CompiledQueryParameter(objectParameter.Key, objectParameter.Value); try { objectQueryParameters.Add(compiledParams[i].ObjectParameter); } catch (ArgumentOutOfRangeException) { // If this is a simple query parameter (involving a single delegate parameter) report the // type of that parameter. Otherwise, report the type of the part of the parameter. HashSet parameters = ParameterExpressionVisitor.FindAllParametersInExpression(objectParameter.Key); Type parameterType = parameters.Count == 1 ? parameters.Single().Type : objectParameter.Value.ParameterType; throw EntityUtil.NotSupported(Strings.CompiledELinq_UnsupportedParameterType(parameterType.FullName)); } i++; } return new CompiledELinqQueryState(elementType, context, objectQueryParameters, compiledParams, lambda, cacheToken); } private CompiledELinqQueryState(Type elementType, ObjectContext context, ObjectParameterCollection objectParameters, CompiledQueryParameter[] compiledParams, LambdaExpression lambda, Guid cacheToken) : base(elementType, context, objectParameters, lambda.Body) { Debug.Assert(objectParameters != null, "A parameter collection is required"); _rootContextParameter = lambda.Parameters[0]; _parameters = compiledParams; _cacheToken = cacheToken; // The parameters available to a compiled query are fixed. this.EnsureParameters().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(); DbQueryCommandTree tree = (DbQueryCommandTree)queryExpression.CommandTree; tree.Query = queryExpression; // Prepare the execution plan using the command tree and the computed effective merge option plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan); // 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(); DbQueryCommandTree tree = (DbQueryCommandTree)queryExpression.CommandTree; tree.Query = 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); // 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); } } } 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(base.Expression, ObjectContext, _rootContextParameter, _parameters); } } ///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() { // Create the command tree used for conversion and add the fixed set of parameters to it DbQueryCommandTree tree = new DbQueryCommandTree(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace); foreach (var parameter in _parameters) { parameter.CreateParameterReferenceAndAddParameterToCommandTree(tree, this.ObjectContext.Perspective); } // Initialize a binding context based on the compiled query parameters. BindingContext context = new BindingContext(_rootContextParameter, this.ObjectContext, _parameters); // Return a new expression converter that uses the initialized command tree and binding context. return new ExpressionConverter(this.ObjectContext, context, tree, base.Expression, this.Parameters); } ////// Replaces ParameterExpresion with ConstantExpression /// to make the expression usable as a donor expression /// private sealed class CreateDonateableExpressionVisitor : ExpressionVisitor { private readonly Dictionary_parameterToValueLookup; private readonly BindingContext _bindingContext; private CreateDonateableExpressionVisitor(BindingContext bindingContext, Dictionary parameterToValueLookup) { Debug.Assert(bindingContext != null, "bindingContext must have a value"); Debug.Assert(parameterToValueLookup != null, "parameterToValueLookup must have a value"); _bindingContext = bindingContext; _parameterToValueLookup = parameterToValueLookup; } internal static Expression Replace(Expression input, ObjectContext objectContext, ParameterExpression rootContextParameter, CompiledQueryParameter [] parameters) { BindingContext bindingContext = new BindingContext(rootContextParameter, objectContext, parameters); Dictionary parameterLookup = parameters.ToDictionary(p => p.Expression, p => p.ObjectParameter.Value); var replacer = new CreateDonateableExpressionVisitor(bindingContext, parameterLookup); return replacer.Visit(input); } /// /// Replace all the known (outer scope) Expressions with ConstantExpressions /// /// The Expression to replace ///The new constant expression internal override Expression Visit(Expression expression) { object value; if (null != expression && _parameterToValueLookup.TryGetValue(expression, out value)) { return Expression.Constant(value, expression.Type); } return base.Visit(expression); } internal override Expression VisitMethodCall(MethodCallExpression m) { Expression newExpression; if (TryReplaceRootQuery(m, out newExpression)) { return newExpression; } return base.VisitMethodCall(m); } internal override Expression VisitMemberAccess(MemberExpression m) { Expression newExpression; if (TryReplaceRootQuery(m, out newExpression)) { return newExpression; } return base.VisitMemberAccess(m); } bool TryReplaceRootQuery(Expression expression, out Expression newExpression) { ObjectQuery rootQuery; if (ExpressionEvaluator.TryEvaluateRootQuery(_bindingContext, expression, out rootQuery)) { Debug.Assert(typeof(ObjectQuery).IsAssignableFrom(expression.Type), "how did we get a different type"); newExpression = Expression.Constant(rootQuery, expression.Type); return true; } newExpression = null; return false; } } ////// Collects parameters expressions from a LINQ expression tree. /// private sealed class ParameterExpressionVisitor : ExpressionVisitor { internal readonly HashSet_parameters = new HashSet (); private ParameterExpressionVisitor() { } internal static HashSet FindAllParametersInExpression(Expression expression) { ParameterExpressionVisitor visitor = new ParameterExpressionVisitor(); visitor.Visit(expression); return visitor._parameters; } internal override Expression VisitParameter(ParameterExpression p) { _parameters.Add(p); return base.VisitParameter(p); } } } internal sealed class CompiledQueryParameter { private readonly Expression _expression; private readonly ObjectParameter _parameter; private DbParameterReferenceExpression _parameterReference; internal CompiledQueryParameter(Expression expression, ObjectParameter parameter) { _expression = expression; _parameter = parameter; } /// /// Adds the ObjectParameter to the DbCommandTree, and creates a ParameterReferenceExpression /// to be placed in the proper places in the tree /// /// The command tree to create operate on. /// The ClrPerspective to help get the correct TypeUsage. internal void CreateParameterReferenceAndAddParameterToCommandTree(DbCommandTree commandTree, ClrPerspective perspective) { Debug.Assert(_parameterReference == null, "don't call this once it is already setup"); TypeUsage typeUsage; if(ClosureBinding.TryGetTypeUsageForObjectParameter(_parameter, perspective, out typeUsage)) { commandTree.AddParameter(_parameter.Name, typeUsage); _parameterReference = commandTree.CreateParameterReferenceExpression(_parameter.Name); } Debug.Assert(_parameterReference != null, "Not sure why this would ever happen, and it isn't handled"); } internal Expression Expression { get { return _expression; } } internal ObjectParameter ObjectParameter { get { return _parameter; } } internal DbParameterReferenceExpression ParameterReference { get { return _parameterReference; } } } } // 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
- PersistenceTypeAttribute.cs
- COM2ExtendedUITypeEditor.cs
- Documentation.cs
- NativeMethods.cs
- WebPartMovingEventArgs.cs
- BaseCodeDomTreeGenerator.cs
- OleDbPropertySetGuid.cs
- IdnElement.cs
- RelatedView.cs
- SdlChannelSink.cs
- DiscoveryMessageSequence.cs
- RegionIterator.cs
- ProviderBase.cs
- TraversalRequest.cs
- BasePropertyDescriptor.cs
- ReadOnlyAttribute.cs
- _HeaderInfoTable.cs
- WebControlParameterProxy.cs
- SqlProcedureAttribute.cs
- BaseCAMarshaler.cs
- XslCompiledTransform.cs
- TextTrailingCharacterEllipsis.cs
- StackSpiller.Bindings.cs
- InstallerTypeAttribute.cs
- AuthenticationService.cs
- Marshal.cs
- PolicyException.cs
- Compensate.cs
- ImportContext.cs
- SmiEventSink_Default.cs
- StdRegProviderWrapper.cs
- InkCanvasFeedbackAdorner.cs
- TreeNode.cs
- FixedSOMElement.cs
- ControlPager.cs
- WebExceptionStatus.cs
- ArglessEventHandlerProxy.cs
- PageWrapper.cs
- StreamedWorkflowDefinitionContext.cs
- Base64Decoder.cs
- BufferBuilder.cs
- Marshal.cs
- AutomationPropertyChangedEventArgs.cs
- EditorPartChrome.cs
- Ref.cs
- CodePrimitiveExpression.cs
- DocumentScope.cs
- XmlWriter.cs
- ListControl.cs
- PipelineModuleStepContainer.cs
- wpf-etw.cs
- XmlChildEnumerator.cs
- IntegerCollectionEditor.cs
- SafeBitVector32.cs
- MultiPropertyDescriptorGridEntry.cs
- Deflater.cs
- Manipulation.cs
- IndexOutOfRangeException.cs
- WebBrowserNavigatingEventHandler.cs
- ScriptControlDescriptor.cs
- HtmlLink.cs
- XamlRtfConverter.cs
- IPipelineRuntime.cs
- GeneratedView.cs
- PersonalizableAttribute.cs
- ExceptionValidationRule.cs
- WindowsGrip.cs
- RectangleConverter.cs
- SafeViewOfFileHandle.cs
- _TimerThread.cs
- recordstatefactory.cs
- AlgoModule.cs
- TableLayoutStyle.cs
- TrackingLocation.cs
- ResXDataNode.cs
- InternalConfigHost.cs
- StringFunctions.cs
- TableLayoutPanelDesigner.cs
- RegexBoyerMoore.cs
- ParseNumbers.cs
- WindowsTreeView.cs
- WebPartManager.cs
- OracleParameter.cs
- IpcClientManager.cs
- ExpressionBuilder.cs
- MetadataAssemblyHelper.cs
- MemberJoinTreeNode.cs
- TextFormatter.cs
- EndOfStreamException.cs
- TextRangeEditLists.cs
- EnvelopedPkcs7.cs
- SafeSecurityHandles.cs
- CatalogZone.cs
- CurrentTimeZone.cs
- PropertyChangedEventArgs.cs
- CalculatedColumn.cs
- ProvidersHelper.cs
- TrackingProfileSerializer.cs
- WebCategoryAttribute.cs
- NextPreviousPagerField.cs