ELinqQueryState.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / ELinqQueryState.cs / 1305376 / ELinqQueryState.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.Metadata.Edm;
    using System.Data.Objects; 
    using System.Data.Objects.ELinq; 
    using System.Data.Objects.Internal;
    using System.Diagnostics; 
    using System.Reflection;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Collections.ObjectModel; 

    ///  
    /// Models a Linq to Entities ObjectQuery 
    /// 
    internal class ELinqQueryState : ObjectQueryState 
    {
        #region Private State

        private readonly Expression _expression; 
        private Func _recompileRequired;
        private ReadOnlyCollection> _linqParameters; 
 
        #endregion
 
        #region Constructors

        /// 
        /// Constructs a new ELinqQueryImplementation based on the specified Linq Expression 
        /// against the specified ObjectContext.
        ///  
        /// The element type of the implemented ObjectQuery, as a CLR type. 
        /// The ObjectContext with which the implemented ObjectQuery is associated.
        /// The Linq Expression that defines this query. 
        internal ELinqQueryState(Type elementType, ObjectContext context, Expression expression)
            : base(elementType, context, null, null)
        {
            // 
            // Initialize the LINQ expression, which is passed in via
            // public APIs on ObjectQuery and must be checked here 
            // (the base class performs similar checks on the ObjectContext and MergeOption arguments). 
            //
            EntityUtil.CheckArgumentNull(expression, "expression"); 
            // closure bindings and initializers are explicitly allowed to be null

            _expression = expression;
        } 

        #endregion 
 
        #region ObjectQueryState overrides
 
        protected override TypeUsage GetResultType()
        {
            // Since this method is only called once, on demand, a full conversion pass
            // is performed to produce the DbExpression and return its result type. 
            // This does not affect any cached execution plan or closure bindings that may be present.
            ExpressionConverter converter = this.CreateExpressionConverter(); 
            return converter.Convert().ResultType; 
        }
 
        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?");
 
            // If this query has already been prepared, its current execution plan may no longer be valid.
            ObjectQueryExecutionPlan plan = this._cachedPlan; 
            if (plan != null) 
            {
                // Was a merge option specified in the call to Execute(MergeOption) or set via ObjectQuery.MergeOption? 
                MergeOption? explicitMergeOption = GetMergeOption(forMergeOption, this.UserSpecifiedMergeOption);

                // If a merge option was explicitly specified, and it does not match the plan's merge option, then the plan is no longer valid.
                if((explicitMergeOption.HasValue && 
                    explicitMergeOption.Value != plan.MergeOption) ||
                   this._recompileRequired()) 
                { 
                    plan = null;
                } 
            }

            // The plan may have been invalidated above, or this query may never have been prepared.
            if (plan == null) 
            {
                // Metadata is required to generate the execution plan. 
                this.ObjectContext.EnsureMetadata(); 

                // Reset internal state 
                this._recompileRequired = null;
                this.ResetParameters();

                // Translate LINQ expression to a DbExpression 
                ExpressionConverter converter = this.CreateExpressionConverter();
                DbExpression queryExpression = converter.Convert(); 
 
                // This delegate tells us when a part of the expression tree has changed requiring a recompile.
                this._recompileRequired = converter.RecompileRequired; 

                // Determine the merge option, with the following precedence:
                // 1. A merge option was specified explicitly as the argument to Execute(MergeOption).
                // 2. The user has set the MergeOption property on the ObjectQuery instance. 
                // 3. A merge option has been extracted from the 'root' query and propagated to the root of the expression tree.
                // 4. The global default merge option. 
                MergeOption mergeOption = EnsureMergeOption(forMergeOption, 
                                                            this.UserSpecifiedMergeOption,
                                                            converter.PropagatedMergeOption); 

                // If parameters were aggregated from referenced (non-LINQ) ObjectQuery instances then add them to the parameters collection
                _linqParameters = converter.GetParameters();
                if (_linqParameters != null && _linqParameters.Count > 0) 
                {
                    ObjectParameterCollection currentParams = this.EnsureParameters(); 
                    currentParams.SetReadOnly(false); 
                    foreach (KeyValuePair pair in _linqParameters)
                    { 
                        // Note that it is safe to add the parameter directly only
                        // because parameters are cloned before they are added to the
                        // converter's parameter collection, or they came from this
                        // instance's parameter collection in the first place. 
                        ObjectParameter convertedParam = pair.Key;
                        currentParams.Add(convertedParam); 
                    } 
                    currentParams.SetReadOnly(true);
                } 

                DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression);
                plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan, null);
                this._cachedPlan = plan; 
            }
 
            if (_linqParameters != null) 
            {
                foreach (KeyValuePair pair in _linqParameters) 
                {
                    ObjectParameter parameter = pair.Key;
                    QueryParameterExpression parameterExpression = pair.Value;
                    if (null != parameterExpression) 
                    {
                        parameter.Value = parameterExpression.EvaluateParameter(null); 
                    } 
                }
            } 

            return plan;
        }
 
        /// 
        /// Returns a new ObjectQueryState instance with the specified navigation property path specified as an Include span. 
        /// For eLINQ queries the Include operation is modelled as a method call expression applied to the source ObectQuery, 
        /// so the  property is always null on the returned instance.
        ///  
        /// The element type of the resulting query
        /// The ObjectQuery on which Include was called; required to build the new method call expression
        /// The new Include path
        /// A new ObjectQueryState instance that incorporates the Include path, in this case a new method call expression 
        internal override ObjectQueryState Include(ObjectQuery sourceQuery, string includePath)
        { 
            MethodInfo includeMethod = sourceQuery.GetType().GetMethod("Include", BindingFlags.Public | BindingFlags.Instance); 
            Debug.Assert(includeMethod != null, "Unable to find ObjectQuery.Include method?");
 
            Expression includeCall = Expression.Call(Expression.Constant(sourceQuery), includeMethod, new Expression[] { Expression.Constant(includePath, typeof(string)) });
            ObjectQueryState retState = new ELinqQueryState(this.ElementType, this.ObjectContext, includeCall);
            this.ApplySettingsTo(retState);
            return retState; 
        }
 
        ///  
        /// eLINQ queries do not have command text. This method always returns false.
        ///  
        /// Always set to null
        /// Always returns false
        internal override bool TryGetCommandText(out string commandText)
        { 
            commandText = null;
            return false; 
        } 

        ///  
        /// Gets the LINQ Expression that defines this query for external (of ObjectQueryState) use.
        /// Note that the  property is used, which is overridden by compiled eLINQ
        /// queries to produce an Expression tree where parameter references have been replaced with constants.
        ///  
        /// The LINQ expression that describes this query
        /// Always returns true 
        internal override bool TryGetExpression(out System.Linq.Expressions.Expression expression) 
        {
            expression = this.Expression; 
            return true;
        }

        #endregion 

        internal virtual Expression Expression { get { return _expression; } } 
 
        protected virtual ExpressionConverter CreateExpressionConverter()
        { 
            Funcletizer funcletizer = Funcletizer.CreateQueryFuncletizer(this.ObjectContext);
            return new ExpressionConverter(funcletizer, _expression);
        }
 
        private void ResetParameters()
        { 
            if (this.Parameters != null) 
            {
                bool wasLocked = ((ICollection)this.Parameters).IsReadOnly; 
                if (wasLocked)
                {
                    this.Parameters.SetReadOnly(false);
                } 
                this.Parameters.Clear();
                if (wasLocked) 
                { 
                    this.Parameters.SetReadOnly(true);
                } 
            }
            _linqParameters = null;
        }
    } 
}

// 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.Metadata.Edm;
    using System.Data.Objects; 
    using System.Data.Objects.ELinq; 
    using System.Data.Objects.Internal;
    using System.Diagnostics; 
    using System.Reflection;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Collections.ObjectModel; 

    ///  
    /// Models a Linq to Entities ObjectQuery 
    /// 
    internal class ELinqQueryState : ObjectQueryState 
    {
        #region Private State

        private readonly Expression _expression; 
        private Func _recompileRequired;
        private ReadOnlyCollection> _linqParameters; 
 
        #endregion
 
        #region Constructors

        /// 
        /// Constructs a new ELinqQueryImplementation based on the specified Linq Expression 
        /// against the specified ObjectContext.
        ///  
        /// The element type of the implemented ObjectQuery, as a CLR type. 
        /// The ObjectContext with which the implemented ObjectQuery is associated.
        /// The Linq Expression that defines this query. 
        internal ELinqQueryState(Type elementType, ObjectContext context, Expression expression)
            : base(elementType, context, null, null)
        {
            // 
            // Initialize the LINQ expression, which is passed in via
            // public APIs on ObjectQuery and must be checked here 
            // (the base class performs similar checks on the ObjectContext and MergeOption arguments). 
            //
            EntityUtil.CheckArgumentNull(expression, "expression"); 
            // closure bindings and initializers are explicitly allowed to be null

            _expression = expression;
        } 

        #endregion 
 
        #region ObjectQueryState overrides
 
        protected override TypeUsage GetResultType()
        {
            // Since this method is only called once, on demand, a full conversion pass
            // is performed to produce the DbExpression and return its result type. 
            // This does not affect any cached execution plan or closure bindings that may be present.
            ExpressionConverter converter = this.CreateExpressionConverter(); 
            return converter.Convert().ResultType; 
        }
 
        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?");
 
            // If this query has already been prepared, its current execution plan may no longer be valid.
            ObjectQueryExecutionPlan plan = this._cachedPlan; 
            if (plan != null) 
            {
                // Was a merge option specified in the call to Execute(MergeOption) or set via ObjectQuery.MergeOption? 
                MergeOption? explicitMergeOption = GetMergeOption(forMergeOption, this.UserSpecifiedMergeOption);

                // If a merge option was explicitly specified, and it does not match the plan's merge option, then the plan is no longer valid.
                if((explicitMergeOption.HasValue && 
                    explicitMergeOption.Value != plan.MergeOption) ||
                   this._recompileRequired()) 
                { 
                    plan = null;
                } 
            }

            // The plan may have been invalidated above, or this query may never have been prepared.
            if (plan == null) 
            {
                // Metadata is required to generate the execution plan. 
                this.ObjectContext.EnsureMetadata(); 

                // Reset internal state 
                this._recompileRequired = null;
                this.ResetParameters();

                // Translate LINQ expression to a DbExpression 
                ExpressionConverter converter = this.CreateExpressionConverter();
                DbExpression queryExpression = converter.Convert(); 
 
                // This delegate tells us when a part of the expression tree has changed requiring a recompile.
                this._recompileRequired = converter.RecompileRequired; 

                // Determine the merge option, with the following precedence:
                // 1. A merge option was specified explicitly as the argument to Execute(MergeOption).
                // 2. The user has set the MergeOption property on the ObjectQuery instance. 
                // 3. A merge option has been extracted from the 'root' query and propagated to the root of the expression tree.
                // 4. The global default merge option. 
                MergeOption mergeOption = EnsureMergeOption(forMergeOption, 
                                                            this.UserSpecifiedMergeOption,
                                                            converter.PropagatedMergeOption); 

                // If parameters were aggregated from referenced (non-LINQ) ObjectQuery instances then add them to the parameters collection
                _linqParameters = converter.GetParameters();
                if (_linqParameters != null && _linqParameters.Count > 0) 
                {
                    ObjectParameterCollection currentParams = this.EnsureParameters(); 
                    currentParams.SetReadOnly(false); 
                    foreach (KeyValuePair pair in _linqParameters)
                    { 
                        // Note that it is safe to add the parameter directly only
                        // because parameters are cloned before they are added to the
                        // converter's parameter collection, or they came from this
                        // instance's parameter collection in the first place. 
                        ObjectParameter convertedParam = pair.Key;
                        currentParams.Add(convertedParam); 
                    } 
                    currentParams.SetReadOnly(true);
                } 

                DbQueryCommandTree tree = DbQueryCommandTree.FromValidExpression(this.ObjectContext.MetadataWorkspace, DataSpace.CSpace, queryExpression);
                plan = ObjectQueryExecutionPlan.Prepare(this.ObjectContext, tree, this.ElementType, mergeOption, converter.PropagatedSpan, null);
                this._cachedPlan = plan; 
            }
 
            if (_linqParameters != null) 
            {
                foreach (KeyValuePair pair in _linqParameters) 
                {
                    ObjectParameter parameter = pair.Key;
                    QueryParameterExpression parameterExpression = pair.Value;
                    if (null != parameterExpression) 
                    {
                        parameter.Value = parameterExpression.EvaluateParameter(null); 
                    } 
                }
            } 

            return plan;
        }
 
        /// 
        /// Returns a new ObjectQueryState instance with the specified navigation property path specified as an Include span. 
        /// For eLINQ queries the Include operation is modelled as a method call expression applied to the source ObectQuery, 
        /// so the  property is always null on the returned instance.
        ///  
        /// The element type of the resulting query
        /// The ObjectQuery on which Include was called; required to build the new method call expression
        /// The new Include path
        /// A new ObjectQueryState instance that incorporates the Include path, in this case a new method call expression 
        internal override ObjectQueryState Include(ObjectQuery sourceQuery, string includePath)
        { 
            MethodInfo includeMethod = sourceQuery.GetType().GetMethod("Include", BindingFlags.Public | BindingFlags.Instance); 
            Debug.Assert(includeMethod != null, "Unable to find ObjectQuery.Include method?");
 
            Expression includeCall = Expression.Call(Expression.Constant(sourceQuery), includeMethod, new Expression[] { Expression.Constant(includePath, typeof(string)) });
            ObjectQueryState retState = new ELinqQueryState(this.ElementType, this.ObjectContext, includeCall);
            this.ApplySettingsTo(retState);
            return retState; 
        }
 
        ///  
        /// eLINQ queries do not have command text. This method always returns false.
        ///  
        /// Always set to null
        /// Always returns false
        internal override bool TryGetCommandText(out string commandText)
        { 
            commandText = null;
            return false; 
        } 

        ///  
        /// Gets the LINQ Expression that defines this query for external (of ObjectQueryState) use.
        /// Note that the  property is used, which is overridden by compiled eLINQ
        /// queries to produce an Expression tree where parameter references have been replaced with constants.
        ///  
        /// The LINQ expression that describes this query
        /// Always returns true 
        internal override bool TryGetExpression(out System.Linq.Expressions.Expression expression) 
        {
            expression = this.Expression; 
            return true;
        }

        #endregion 

        internal virtual Expression Expression { get { return _expression; } } 
 
        protected virtual ExpressionConverter CreateExpressionConverter()
        { 
            Funcletizer funcletizer = Funcletizer.CreateQueryFuncletizer(this.ObjectContext);
            return new ExpressionConverter(funcletizer, _expression);
        }
 
        private void ResetParameters()
        { 
            if (this.Parameters != null) 
            {
                bool wasLocked = ((ICollection)this.Parameters).IsReadOnly; 
                if (wasLocked)
                {
                    this.Parameters.SetReadOnly(false);
                } 
                this.Parameters.Clear();
                if (wasLocked) 
                { 
                    this.Parameters.SetReadOnly(true);
                } 
            }
            _linqParameters = null;
        }
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK