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.