Code:
/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / 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
- DataGridViewDataErrorEventArgs.cs
- XPathNodePointer.cs
- XmlProcessingInstruction.cs
- BaseTemplatedMobileComponentEditor.cs
- OutputCacheSettingsSection.cs
- FastEncoderWindow.cs
- LocatorPart.cs
- DesignerLinkAdapter.cs
- ZipIOZip64EndOfCentralDirectoryBlock.cs
- SequentialWorkflowRootDesigner.cs
- BufferCache.cs
- GeometryConverter.cs
- PageCache.cs
- CTreeGenerator.cs
- OraclePermission.cs
- OperatorExpressions.cs
- ImageListUtils.cs
- EmptyQuery.cs
- CommandField.cs
- FileDialogCustomPlace.cs
- ButtonColumn.cs
- ValueUnavailableException.cs
- SQLBytes.cs
- AdjustableArrowCap.cs
- DocumentPage.cs
- ReadOnlyHierarchicalDataSourceView.cs
- dataprotectionpermission.cs
- Point3DKeyFrameCollection.cs
- ByteStreamMessageEncoder.cs
- SecurityPolicySection.cs
- BinHexDecoder.cs
- IImplicitResourceProvider.cs
- MachineKeySection.cs
- Span.cs
- Quad.cs
- SafeNativeMethodsOther.cs
- TextServicesHost.cs
- MappingMetadataHelper.cs
- StickyNote.cs
- Stacktrace.cs
- PaintEvent.cs
- TextAnchor.cs
- _DigestClient.cs
- EditingScope.cs
- StrictModeSecurityHeaderElementInferenceEngine.cs
- VSWCFServiceContractGenerator.cs
- ISAPIWorkerRequest.cs
- TextEditorCharacters.cs
- FillErrorEventArgs.cs
- HttpRuntime.cs
- LineUtil.cs
- GuidelineSet.cs
- GenericRootAutomationPeer.cs
- PermissionRequestEvidence.cs
- QueueProcessor.cs
- LayoutSettings.cs
- Transaction.cs
- RowBinding.cs
- TransactionManager.cs
- RenderContext.cs
- Point3DConverter.cs
- lengthconverter.cs
- FileVersion.cs
- ProviderMetadataCachedInformation.cs
- QueryCacheManager.cs
- KeySpline.cs
- Popup.cs
- SqlInternalConnection.cs
- NonBatchDirectoryCompiler.cs
- DiscoveryMessageSequence11.cs
- StringConverter.cs
- FilteredAttributeCollection.cs
- XamlFilter.cs
- TypeLoadException.cs
- Catch.cs
- CaseInsensitiveHashCodeProvider.cs
- regiisutil.cs
- TableColumnCollection.cs
- DataGridrowEditEndingEventArgs.cs
- NegotiationTokenProvider.cs
- FontSource.cs
- HatchBrush.cs
- ContentType.cs
- Site.cs
- ErasingStroke.cs
- SystemException.cs
- FormatVersion.cs
- UnsupportedPolicyOptionsException.cs
- SqlLiftIndependentRowExpressions.cs
- SHA384.cs
- JournalEntryListConverter.cs
- SqlComparer.cs
- NeutralResourcesLanguageAttribute.cs
- XsdDateTime.cs
- CompensationParticipant.cs
- SqlDataAdapter.cs
- DeviceContexts.cs
- EDesignUtil.cs
- DecimalStorage.cs
- ViewBase.cs