CompiledQuery.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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 / CompiledQuery.cs / 1 / CompiledQuery.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....]
// @backupowner [....] 
//--------------------------------------------------------------------- 
using System;
using System.Collections.Generic; 
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Data.Objects.ELinq; 
using System.Diagnostics;
using System.Data.Objects.Internal; 
using OM = System.Collections.ObjectModel; 

namespace System.Data.Objects 
{
    /// 
    /// Caches an ELinq query
    ///  
    public sealed class CompiledQuery
    { 
        // NOTE: make sure all changes to this object keep it immutable 
        //       so it won't have any thread saftey concerns
        private readonly LambdaExpression _query; 
        private readonly Guid _cacheToken = Guid.NewGuid();
        private readonly OM.ReadOnlyCollection _parameters;

        ///  
        /// Constructs a new compiled query instance which hosts the delegate returned to the user
        /// (one of the Invoke overloads). 
        ///  
        /// Compiled query expression.
        /// The type of the delegate producing parameter values from CompiledQuery 
        /// delegate arguments. For details, see CompiledQuery.Parameter.CreateObjectParameter.
        private CompiledQuery(LambdaExpression query, Type parameterDelegateType)
        {
            // lock down query 
            query = LockDown(query);
 
            // find parameter expressions in the query 
            OM.ReadOnlyCollection parameters = CompiledQuery.Parameter.FindParameters(query, parameterDelegateType);
 
            _query = query;
            _parameters = parameters;
        }
 
        private static LambdaExpression LockDown(LambdaExpression query)
        { 
            Expression newBody = LinqTreeNodeEvaluator.EvaluateClosuresAndClientEvalNodes(query.Body); 
            return Expression.Lambda(newBody, query.Parameters.ToArray());
        } 

        /// 
        /// Creates a CompiledQuery delegate from an ELinq expression.
        ///  
        /// An ObjectContext derived type
        /// The scalar type of parameter 1. 
        /// The scalar type of parameter 2. 
        /// The scalar type of parameter 3.
        /// The return type of the delegate. 
        /// The lambda expression to compile.
        /// The CompiledQuery delegate.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification="required for this feature")]
        public static Func Compile(Expression> query) where TArg0 : ObjectContext 
        {
            return new CompiledQuery(query, typeof(Func)).Invoke; 
        } 

        ///  
        /// Creates a CompiledQuery delegate from an ELinq expression.
        /// 
        /// An ObjectContext derived type
        /// The scalar type of parameter 1. 
        /// The scalar type of parameter 2.
        /// The return type of the delegate. 
        /// The lambda expression to compile. 
        /// The CompiledQuery delegate.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")] 
        public static Func Compile(Expression> query) where TArg0 : ObjectContext
        {
            return new CompiledQuery(query, typeof(Func)).Invoke;
        } 

        ///  
        /// Creates a CompiledQuery delegate from an ELinq expression. 
        /// 
        /// An ObjectContext derived type 
        /// The scalar type of parameter 1.
        /// The return type of the delegate.
        /// The lambda expression to compile.
        /// The CompiledQuery delegate. 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")]
        public static Func Compile(Expression> query) where TArg0 : ObjectContext 
        { 
            return new CompiledQuery(query, typeof(Func)).Invoke;
        } 

        /// 
        /// Creates a CompiledQuery delegate from an ELinq expression.
        ///  
        /// An ObjectContext derived type
        /// The return type of the delegate. 
        /// The lambda expression to compile. 
        /// The CompiledQuery delegate.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")] 
        public static Func Compile(Expression> query) where TArg0 : ObjectContext
        {
            return new CompiledQuery(query, typeof(Func)).Invoke;
        } 

        private TResult Invoke(TArg0 arg0) where TArg0 : ObjectContext 
        { 
            EntityUtil.CheckArgumentNull(arg0, "arg0");
 
            // SQLBUDT 447285: Ensure the assembly containing the entity's CLR type is loaded into the workspace.
            // This method must ensure that the O-Space metadata for TResultType is correctly loaded - it is the equivalent
            // of a public constructor for compiled queries, since it is returned as a delegate and called as a public entry point.
            arg0.MetadataWorkspace.LoadAssemblyForType(typeof(TResult), System.Reflection.Assembly.GetCallingAssembly()); 

            return ExecuteQuery(arg0); 
        } 

        private TResult Invoke(TArg0 arg0, TArg1 arg1) where TArg0 : ObjectContext 
        {
            EntityUtil.CheckArgumentNull(arg0, "arg0");

            // SQLBUDT 447285: Ensure the assembly containing the entity's CLR type is loaded into the workspace. 
            // This method must ensure that the O-Space metadata for TResultType is correctly loaded - it is the equivalent
            // of a public constructor for compiled queries, since it is returned as a delegate and called as a public entry point. 
            arg0.MetadataWorkspace.LoadAssemblyForType(typeof(TResult), System.Reflection.Assembly.GetCallingAssembly()); 

            return ExecuteQuery(arg0, arg1); 
        }

        private TResult Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2) where TArg0 : ObjectContext
        { 
            EntityUtil.CheckArgumentNull(arg0, "arg0");
 
            // SQLBUDT 447285: Ensure the assembly containing the entity's CLR type is loaded into the workspace. 
            // This method must ensure that the O-Space metadata for TResultType is correctly loaded - it is the equivalent
            // of a public constructor for compiled queries, since it is returned as a delegate and called as a public entry point. 
            arg0.MetadataWorkspace.LoadAssemblyForType(typeof(TResult), System.Reflection.Assembly.GetCallingAssembly());

            return ExecuteQuery(arg0, arg1, arg2);
        } 

        private TResult Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3) where TArg0 : ObjectContext 
        { 
            EntityUtil.CheckArgumentNull(arg0, "arg0");
 
            // SQLBUDT 447285: Ensure the assembly containing the entity's CLR type is loaded into the workspace.
            // This method must ensure that the O-Space metadata for TResultType is correctly loaded - it is the equivalent
            // of a public constructor for compiled queries, since it is returned as a delegate and called as a public entry point.
            arg0.MetadataWorkspace.LoadAssemblyForType(typeof(TResult), System.Reflection.Assembly.GetCallingAssembly()); 

            return ExecuteQuery(arg0, arg1, arg2, arg3); 
        } 

        private TResult ExecuteQuery(ObjectContext context, params object[] parameterValues) 
        {
            Dictionary objectParameters = CreateObjectParameters(parameterValues);

            bool isSingleton; 
            Type elementType = GetElementType(typeof(TResult), out isSingleton);
            ObjectQueryState queryState = CompiledELinqQueryState.Create(elementType, context, _query, objectParameters, _cacheToken); 
            System.Collections.IEnumerable query = queryState.CreateQuery(); 
            if (isSingleton)
            { 
                return ObjectQueryProvider.ExecuteSingle(Enumerable.Cast(query), _query);
            }
            else
            { 
                return (TResult)query;
            } 
        } 

        private Dictionary CreateObjectParameters(object[] parameterValues) 
        {
            Dictionary objectParameters = new Dictionary();
            foreach (Parameter parameter in _parameters)
            { 
                ObjectParameter objectParameter = parameter.CreateObjectParameter(parameterValues);
                objectParameters.Add(parameter.ParameterExpression, objectParameter); 
            } 
            return objectParameters;
        } 

        /// 
        /// This method is trying to distinguish between a set of types and a singleton type
        /// It also has the restriction that to be a set of types, it must be assignable from ObjectQuery<T> 
        /// Otherwise we won't be able to cast our query to the set requested.
        ///  
        /// The type asked for as a result type. 
        /// Is it a set of a type.
        /// The element type to use 
        private static Type GetElementType(Type resultType, out bool isSingleton)
        {
            Type elementType = TypeSystem.GetElementType(resultType);
 
            isSingleton = (elementType == resultType ||
                           !resultType.IsAssignableFrom(typeof(ObjectQuery<>).MakeGenericType(elementType))); 
 
            if (isSingleton)
            { 
                return resultType;
            }
            else
            { 
                return elementType;
            } 
        } 

        ///  
        /// A parameter in a CompiledQuery expression is some sub-expression that should be evaluated every time
        /// the query is evaluated. Each of the instances of this class becomes a parameter in the ObjectQuery.
        /// It might be as simple as a LINQ parameter, e.g. 'id' in:
        /// 
        ///     CompiledQuery.Compile((MyContext c, int id) => c.Products.Where(p => p.id = id));
        /// 
        /// or it could be a sub-expression, e.g. 'myPrm.X' in: 
        ///
        ///     CompiledQuery.Compile((MyContext c, MyPrm myPrm) => c.Products.Where(p => p.X == myPrm.X)); 
        ///
        /// It basically represents the sub-expressions in the CompiledQuery instance that should become ObjectQuery
        /// parameters.
        ///  
        private sealed class Parameter
        { 
            private readonly string _parameterName = ClosureBinding.GenerateParameterName(); 
            private readonly Expression _parameterExpression;
            private readonly Delegate _getValue; 

            private Parameter(Type parameterDelegateType, Expression parameterExpression, ParameterExpression[] argumentExpressions)
            {
                _parameterExpression = parameterExpression; 

                // Create an expression computing the parameter value based on the compiled query parameters. 
                // We convert to object because this is what the ObjectParameter class takes. 
                parameterExpression = Expression.Convert(parameterExpression, typeof(object));
                LambdaExpression getValueExpression = Expression.Lambda(parameterDelegateType, parameterExpression, argumentExpressions); 
                _getValue = (Delegate)(object)getValueExpression.Compile();
            }

            ///  
            /// Gets the expression within the query that is bound to this parameter.
            ///  
            internal Expression ParameterExpression 
            {
                get { return this._parameterExpression; } 
            }

            /// 
            /// Returns an instance of an ObjectQuery parameter given CLR parameters passed into the 
            /// CompiledQuery delegate.
            ///  
            ///  
            /// Note that there is a many-to-many relationship between CLR parameters and ObjectQuery
            /// parameters. We model this situation using a delegate for every query parameter that takes 
            /// all CLR parameters (parameterValues) and return an ObjectParameter instance. Here's an
            /// example to illustrate:
            ///
            ///     var cq = CompiledQuery((MyContext ctx, int year, int month, int day) => new DateTime(year, month, day) 
            ///
            /// has a single ObjectParameter associated with it with the following delegate: 
            /// 
            ///     (year, month, day) => new DateTime(year, month, day)
            /// 
            /// Another example:
            ///
            ///     var cq = CompiledQuery((MyContext ctx, Department department, Product product) =>
            ///         ctx.Employee.Where(e => e.Department.Name == department.Name || 
            ///         e.WorksOn.Any(prod => product.Department.Name == prod.Department.Name)));
            /// 
            /// has the following primitve ObjectParameters: 
            ///
            ///     (department, product) => department.Name 
            ///     (department, product) => product.Department.Name
            ///
            /// Note that the delegate is always with respect to all of the compiled query arguments whether
            /// or not they're used in the delegate body. 
            ///
            /// The underlying delegate is always called with DynamicInvoke, which takes its arguments from 
            /// an object array. This allows us to share code between all of the Invoke overloads on CompiledQuery 
            /// without having separate typed classes (e.g. a Parameter(Of Arg1), a Parameter(Of Arg1, Arg2), etc.)
            ///  
            /// CLR parameter values from compiled query delegate.
            /// ObjectQuery parameter.
            internal ObjectParameter CreateObjectParameter(object[] parameterValues)
            { 
                ObjectParameter objectParameter = new ObjectParameter(_parameterName, this.ParameterExpression.Type);
                objectParameter.Value = _getValue.DynamicInvoke(parameterValues); 
                return objectParameter; 
            }
 
            /// 
            /// Given a compiled query expression, returns all parameters contained in the expression.
            /// 
            internal static OM.ReadOnlyCollection FindParameters(LambdaExpression query, Type parameterDelegateType) 
            {
                // Gather the arguments that can be used to determine parameter values (all arguments 
                // to the CompiledQuery delegate except for the first argument which is the ObjectContext) 
                ParameterExpression[] argumentExpressions = query.Parameters.Skip(1).ToArray();
 
                // Find subtrees that are legal expressions.
                // A parameter expression must be evaluatable on the client and may contain 'closure' style expressions
                // (i.e. member paths) and value arguments to the query (i.e. everything but the first query
                // parameter). 

                // Note: at this point we've already funcletized sub-expressions (via CompiledQuery.LockDown) 
                // that are client evaluatable or closure references. This additional nomination pass therefore 
                // identifies only those sub-expressions that also include parameter expressions.
                HashSet parameterExpressions = LinqMaximalSubtreeNominator.FindMaximalSubtrees( 
                    query,
                    e => ExpressionEvaluator.IsExpressionNodeClientEvaluatable(e) ||
                        ExpressionEvaluator.IsExpressionNodeAClosure(e) ||
                        (null != e && e.NodeType == ExpressionType.Parameter && argumentExpressions.Contains((ParameterExpression)e))); 

                // Construct parameters 
                List parameters = new List(parameterExpressions.Count); 
                foreach (Expression parameterExpression in parameterExpressions)
                { 
                    // We omit constants (they're just values
                    if (parameterExpression.NodeType != ExpressionType.Constant)
                    {
                        parameters.Add(new Parameter(parameterDelegateType, parameterExpression, argumentExpressions)); 
                    }
                } 
 
                return parameters.AsReadOnly();
            } 
        }
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner [....]
// @backupowner [....] 
//--------------------------------------------------------------------- 
using System;
using System.Collections.Generic; 
using System.Linq;
using System.Text;
using System.Linq.Expressions;
using System.Data.Objects.ELinq; 
using System.Diagnostics;
using System.Data.Objects.Internal; 
using OM = System.Collections.ObjectModel; 

namespace System.Data.Objects 
{
    /// 
    /// Caches an ELinq query
    ///  
    public sealed class CompiledQuery
    { 
        // NOTE: make sure all changes to this object keep it immutable 
        //       so it won't have any thread saftey concerns
        private readonly LambdaExpression _query; 
        private readonly Guid _cacheToken = Guid.NewGuid();
        private readonly OM.ReadOnlyCollection _parameters;

        ///  
        /// Constructs a new compiled query instance which hosts the delegate returned to the user
        /// (one of the Invoke overloads). 
        ///  
        /// Compiled query expression.
        /// The type of the delegate producing parameter values from CompiledQuery 
        /// delegate arguments. For details, see CompiledQuery.Parameter.CreateObjectParameter.
        private CompiledQuery(LambdaExpression query, Type parameterDelegateType)
        {
            // lock down query 
            query = LockDown(query);
 
            // find parameter expressions in the query 
            OM.ReadOnlyCollection parameters = CompiledQuery.Parameter.FindParameters(query, parameterDelegateType);
 
            _query = query;
            _parameters = parameters;
        }
 
        private static LambdaExpression LockDown(LambdaExpression query)
        { 
            Expression newBody = LinqTreeNodeEvaluator.EvaluateClosuresAndClientEvalNodes(query.Body); 
            return Expression.Lambda(newBody, query.Parameters.ToArray());
        } 

        /// 
        /// Creates a CompiledQuery delegate from an ELinq expression.
        ///  
        /// An ObjectContext derived type
        /// The scalar type of parameter 1. 
        /// The scalar type of parameter 2. 
        /// The scalar type of parameter 3.
        /// The return type of the delegate. 
        /// The lambda expression to compile.
        /// The CompiledQuery delegate.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification="required for this feature")]
        public static Func Compile(Expression> query) where TArg0 : ObjectContext 
        {
            return new CompiledQuery(query, typeof(Func)).Invoke; 
        } 

        ///  
        /// Creates a CompiledQuery delegate from an ELinq expression.
        /// 
        /// An ObjectContext derived type
        /// The scalar type of parameter 1. 
        /// The scalar type of parameter 2.
        /// The return type of the delegate. 
        /// The lambda expression to compile. 
        /// The CompiledQuery delegate.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")] 
        public static Func Compile(Expression> query) where TArg0 : ObjectContext
        {
            return new CompiledQuery(query, typeof(Func)).Invoke;
        } 

        ///  
        /// Creates a CompiledQuery delegate from an ELinq expression. 
        /// 
        /// An ObjectContext derived type 
        /// The scalar type of parameter 1.
        /// The return type of the delegate.
        /// The lambda expression to compile.
        /// The CompiledQuery delegate. 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")]
        public static Func Compile(Expression> query) where TArg0 : ObjectContext 
        { 
            return new CompiledQuery(query, typeof(Func)).Invoke;
        } 

        /// 
        /// Creates a CompiledQuery delegate from an ELinq expression.
        ///  
        /// An ObjectContext derived type
        /// The return type of the delegate. 
        /// The lambda expression to compile. 
        /// The CompiledQuery delegate.
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters", Justification = "required for this feature")] 
        public static Func Compile(Expression> query) where TArg0 : ObjectContext
        {
            return new CompiledQuery(query, typeof(Func)).Invoke;
        } 

        private TResult Invoke(TArg0 arg0) where TArg0 : ObjectContext 
        { 
            EntityUtil.CheckArgumentNull(arg0, "arg0");
 
            // SQLBUDT 447285: Ensure the assembly containing the entity's CLR type is loaded into the workspace.
            // This method must ensure that the O-Space metadata for TResultType is correctly loaded - it is the equivalent
            // of a public constructor for compiled queries, since it is returned as a delegate and called as a public entry point.
            arg0.MetadataWorkspace.LoadAssemblyForType(typeof(TResult), System.Reflection.Assembly.GetCallingAssembly()); 

            return ExecuteQuery(arg0); 
        } 

        private TResult Invoke(TArg0 arg0, TArg1 arg1) where TArg0 : ObjectContext 
        {
            EntityUtil.CheckArgumentNull(arg0, "arg0");

            // SQLBUDT 447285: Ensure the assembly containing the entity's CLR type is loaded into the workspace. 
            // This method must ensure that the O-Space metadata for TResultType is correctly loaded - it is the equivalent
            // of a public constructor for compiled queries, since it is returned as a delegate and called as a public entry point. 
            arg0.MetadataWorkspace.LoadAssemblyForType(typeof(TResult), System.Reflection.Assembly.GetCallingAssembly()); 

            return ExecuteQuery(arg0, arg1); 
        }

        private TResult Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2) where TArg0 : ObjectContext
        { 
            EntityUtil.CheckArgumentNull(arg0, "arg0");
 
            // SQLBUDT 447285: Ensure the assembly containing the entity's CLR type is loaded into the workspace. 
            // This method must ensure that the O-Space metadata for TResultType is correctly loaded - it is the equivalent
            // of a public constructor for compiled queries, since it is returned as a delegate and called as a public entry point. 
            arg0.MetadataWorkspace.LoadAssemblyForType(typeof(TResult), System.Reflection.Assembly.GetCallingAssembly());

            return ExecuteQuery(arg0, arg1, arg2);
        } 

        private TResult Invoke(TArg0 arg0, TArg1 arg1, TArg2 arg2, TArg3 arg3) where TArg0 : ObjectContext 
        { 
            EntityUtil.CheckArgumentNull(arg0, "arg0");
 
            // SQLBUDT 447285: Ensure the assembly containing the entity's CLR type is loaded into the workspace.
            // This method must ensure that the O-Space metadata for TResultType is correctly loaded - it is the equivalent
            // of a public constructor for compiled queries, since it is returned as a delegate and called as a public entry point.
            arg0.MetadataWorkspace.LoadAssemblyForType(typeof(TResult), System.Reflection.Assembly.GetCallingAssembly()); 

            return ExecuteQuery(arg0, arg1, arg2, arg3); 
        } 

        private TResult ExecuteQuery(ObjectContext context, params object[] parameterValues) 
        {
            Dictionary objectParameters = CreateObjectParameters(parameterValues);

            bool isSingleton; 
            Type elementType = GetElementType(typeof(TResult), out isSingleton);
            ObjectQueryState queryState = CompiledELinqQueryState.Create(elementType, context, _query, objectParameters, _cacheToken); 
            System.Collections.IEnumerable query = queryState.CreateQuery(); 
            if (isSingleton)
            { 
                return ObjectQueryProvider.ExecuteSingle(Enumerable.Cast(query), _query);
            }
            else
            { 
                return (TResult)query;
            } 
        } 

        private Dictionary CreateObjectParameters(object[] parameterValues) 
        {
            Dictionary objectParameters = new Dictionary();
            foreach (Parameter parameter in _parameters)
            { 
                ObjectParameter objectParameter = parameter.CreateObjectParameter(parameterValues);
                objectParameters.Add(parameter.ParameterExpression, objectParameter); 
            } 
            return objectParameters;
        } 

        /// 
        /// This method is trying to distinguish between a set of types and a singleton type
        /// It also has the restriction that to be a set of types, it must be assignable from ObjectQuery<T> 
        /// Otherwise we won't be able to cast our query to the set requested.
        ///  
        /// The type asked for as a result type. 
        /// Is it a set of a type.
        /// The element type to use 
        private static Type GetElementType(Type resultType, out bool isSingleton)
        {
            Type elementType = TypeSystem.GetElementType(resultType);
 
            isSingleton = (elementType == resultType ||
                           !resultType.IsAssignableFrom(typeof(ObjectQuery<>).MakeGenericType(elementType))); 
 
            if (isSingleton)
            { 
                return resultType;
            }
            else
            { 
                return elementType;
            } 
        } 

        ///  
        /// A parameter in a CompiledQuery expression is some sub-expression that should be evaluated every time
        /// the query is evaluated. Each of the instances of this class becomes a parameter in the ObjectQuery.
        /// It might be as simple as a LINQ parameter, e.g. 'id' in:
        /// 
        ///     CompiledQuery.Compile((MyContext c, int id) => c.Products.Where(p => p.id = id));
        /// 
        /// or it could be a sub-expression, e.g. 'myPrm.X' in: 
        ///
        ///     CompiledQuery.Compile((MyContext c, MyPrm myPrm) => c.Products.Where(p => p.X == myPrm.X)); 
        ///
        /// It basically represents the sub-expressions in the CompiledQuery instance that should become ObjectQuery
        /// parameters.
        ///  
        private sealed class Parameter
        { 
            private readonly string _parameterName = ClosureBinding.GenerateParameterName(); 
            private readonly Expression _parameterExpression;
            private readonly Delegate _getValue; 

            private Parameter(Type parameterDelegateType, Expression parameterExpression, ParameterExpression[] argumentExpressions)
            {
                _parameterExpression = parameterExpression; 

                // Create an expression computing the parameter value based on the compiled query parameters. 
                // We convert to object because this is what the ObjectParameter class takes. 
                parameterExpression = Expression.Convert(parameterExpression, typeof(object));
                LambdaExpression getValueExpression = Expression.Lambda(parameterDelegateType, parameterExpression, argumentExpressions); 
                _getValue = (Delegate)(object)getValueExpression.Compile();
            }

            ///  
            /// Gets the expression within the query that is bound to this parameter.
            ///  
            internal Expression ParameterExpression 
            {
                get { return this._parameterExpression; } 
            }

            /// 
            /// Returns an instance of an ObjectQuery parameter given CLR parameters passed into the 
            /// CompiledQuery delegate.
            ///  
            ///  
            /// Note that there is a many-to-many relationship between CLR parameters and ObjectQuery
            /// parameters. We model this situation using a delegate for every query parameter that takes 
            /// all CLR parameters (parameterValues) and return an ObjectParameter instance. Here's an
            /// example to illustrate:
            ///
            ///     var cq = CompiledQuery((MyContext ctx, int year, int month, int day) => new DateTime(year, month, day) 
            ///
            /// has a single ObjectParameter associated with it with the following delegate: 
            /// 
            ///     (year, month, day) => new DateTime(year, month, day)
            /// 
            /// Another example:
            ///
            ///     var cq = CompiledQuery((MyContext ctx, Department department, Product product) =>
            ///         ctx.Employee.Where(e => e.Department.Name == department.Name || 
            ///         e.WorksOn.Any(prod => product.Department.Name == prod.Department.Name)));
            /// 
            /// has the following primitve ObjectParameters: 
            ///
            ///     (department, product) => department.Name 
            ///     (department, product) => product.Department.Name
            ///
            /// Note that the delegate is always with respect to all of the compiled query arguments whether
            /// or not they're used in the delegate body. 
            ///
            /// The underlying delegate is always called with DynamicInvoke, which takes its arguments from 
            /// an object array. This allows us to share code between all of the Invoke overloads on CompiledQuery 
            /// without having separate typed classes (e.g. a Parameter(Of Arg1), a Parameter(Of Arg1, Arg2), etc.)
            ///  
            /// CLR parameter values from compiled query delegate.
            /// ObjectQuery parameter.
            internal ObjectParameter CreateObjectParameter(object[] parameterValues)
            { 
                ObjectParameter objectParameter = new ObjectParameter(_parameterName, this.ParameterExpression.Type);
                objectParameter.Value = _getValue.DynamicInvoke(parameterValues); 
                return objectParameter; 
            }
 
            /// 
            /// Given a compiled query expression, returns all parameters contained in the expression.
            /// 
            internal static OM.ReadOnlyCollection FindParameters(LambdaExpression query, Type parameterDelegateType) 
            {
                // Gather the arguments that can be used to determine parameter values (all arguments 
                // to the CompiledQuery delegate except for the first argument which is the ObjectContext) 
                ParameterExpression[] argumentExpressions = query.Parameters.Skip(1).ToArray();
 
                // Find subtrees that are legal expressions.
                // A parameter expression must be evaluatable on the client and may contain 'closure' style expressions
                // (i.e. member paths) and value arguments to the query (i.e. everything but the first query
                // parameter). 

                // Note: at this point we've already funcletized sub-expressions (via CompiledQuery.LockDown) 
                // that are client evaluatable or closure references. This additional nomination pass therefore 
                // identifies only those sub-expressions that also include parameter expressions.
                HashSet parameterExpressions = LinqMaximalSubtreeNominator.FindMaximalSubtrees( 
                    query,
                    e => ExpressionEvaluator.IsExpressionNodeClientEvaluatable(e) ||
                        ExpressionEvaluator.IsExpressionNodeAClosure(e) ||
                        (null != e && e.NodeType == ExpressionType.Parameter && argumentExpressions.Contains((ParameterExpression)e))); 

                // Construct parameters 
                List parameters = new List(parameterExpressions.Count); 
                foreach (Expression parameterExpression in parameterExpressions)
                { 
                    // We omit constants (they're just values
                    if (parameterExpression.NodeType != ExpressionType.Constant)
                    {
                        parameters.Add(new Parameter(parameterDelegateType, parameterExpression, argumentExpressions)); 
                    }
                } 
 
                return parameters.AsReadOnly();
            } 
        }
    }
}

// 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