ExpressionConverter.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / ExpressionConverter.cs / 1305376 / ExpressionConverter.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....]
//--------------------------------------------------------------------- 
 
using System.Linq.Expressions;
using System.Collections.ObjectModel; 
using System.Linq;
using System.Collections.Generic;
using System.Data.Common.CommandTrees;
using System.Data.Metadata.Edm; 
using System.Reflection;
using System.Data.Common.EntitySql; 
using System.Diagnostics; 
using System.Data.Common;
using System.Globalization; 
using System.Data.Common.Utils;
using System.Data.Objects.DataClasses;
using System.Data.Objects.Internal;
using System.Collections; 
using System.Data.Entity;
using System.Text; 
using System.Data.Common.CommandTrees.Internal; 
using System.Data.Common.CommandTrees.ExpressionBuilder;
 
namespace System.Data.Objects.ELinq
{
    /// 
    /// Class supporting conversion of LINQ expressions to EDM CQT expressions. 
    /// 
    internal sealed partial class ExpressionConverter 
    { 
        #region Fields
        private readonly Funcletizer _funcletizer; 
        private readonly Perspective _perspective;
        private readonly Expression _expression;
        private readonly BindingContext _bindingContext;
        private Func _recompileRequired; 
        private List> _parameters;
        private Dictionary _spanMappings; 
        private MergeOption? _mergeOption; 
        private Dictionary _initializers;
        private Span _span; 
        private HashSet _inlineEntitySqlQueries;

        #region Consts
        private const string s_visualBasicAssemblyFullName = 
            "Microsoft.VisualBasic, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a";
        private static readonly Dictionary s_translators = InitializeTranslators(); 
 
        internal const string s_entityCollectionCountPropertyName = "Count";
        internal const string s_nullableHasValuePropertyName = "HasValue"; 
        internal const string s_nullableValuePropertyName = "Value";

        /// 
        /// Gets the name of the key column appearing in ELinq GroupBy projections 
        /// 
        internal const string KeyColumnName = "Key"; 
 
        /// 
        /// Gets the name of the group column appearing in ELinq CQTs (used in GroupBy expressions) 
        /// 
        internal const string GroupColumnName = "Group";

        ///  
        /// Gets the name of the parent column appearing in ELinq EntityCollection projections
        ///  
        internal const string EntityCollectionOwnerColumnName = "Owner"; 

        ///  
        /// Gets the name of the children column appearing in ELinq EntityCollection projections
        /// 
        internal const string EntityCollectionElementsColumnName = "Elements";
 
        /// 
        /// The Edm namespace name, used for canonical functions 
        ///  
        internal const string EdmNamespaceName = "Edm";
        #endregion 

        #region Canonical Function Names
        private const string Concat = "Concat";
        private const string IndexOf = "IndexOf"; 
        private const string Length = "Length";
        private const string Right = "Right"; 
        private const string Substring = "Substring"; 
        private const string ToUpper = "ToUpper";
        private const string ToLower = "ToLower"; 
        private const string LTrim = "LTrim";
        private const string RTrim = "RTrim";
        private const string Reverse = "Reverse";
        private const string BitwiseAnd = "BitwiseAnd"; 
        private const string BitwiseOr = "BitwiseOr";
        private const string BitwiseNot = "BitwiseNot"; 
        private const string BitwiseXor = "BitwiseXor"; 
        private const string CurrentUtcDateTime = "CurrentUtcDateTime";
        private const string CurrentDateTimeOffset = "CurrentDateTimeOffset"; 
        private const string CurrentDateTime = "CurrentDateTime";
        private const string Year = "Year";
        private const string Month = "Month";
        private const string Day = "Day"; 
        private const string Hour = "Hour";
        private const string Minute = "Minute"; 
        private const string Second = "Second"; 
        private const string Millisecond = "Millisecond";
        #endregion 

        #region Additional Entity function names
        private const string AsUnicode = "AsUnicode";
        private const string AsNonUnicode = "AsNonUnicode"; 
        #endregion
        #endregion 
 
        #region Constructors and static initializors
        internal ExpressionConverter(Funcletizer funcletizer, Expression expression) 
        {
            EntityUtil.CheckArgumentNull(funcletizer, "funcletizer");
            EntityUtil.CheckArgumentNull(expression, "expression");
 
            // Funcletize the expression (identify components of the expression that should be evaluated
            // locally) 
            _funcletizer = funcletizer; 
            expression = funcletizer.Funcletize(expression, out _recompileRequired);
 
            // Normalize the expression (replace obfuscated parts of the tree with simpler nodes)
            LinqExpressionNormalizer normalizer = new LinqExpressionNormalizer();
            _expression = normalizer.Visit(expression);
 
            _perspective = funcletizer.RootContext.Perspective;
            _bindingContext = new BindingContext(); 
        } 

        // initialize translator dictionary (which support identification of translators 
        // for LINQ expression node types)
        private static Dictionary InitializeTranslators()
        {
            Dictionary translators = new Dictionary(); 
            foreach (Translator translator in GetTranslators())
            { 
                foreach (ExpressionType nodeType in translator.NodeTypes) 
                {
                    translators.Add(nodeType, translator); 
                }
            }

            return translators; 
        }
 
        private static IEnumerable GetTranslators() 
        {
            yield return new AndAlsoTranslator(); 
            yield return new OrElseTranslator();
            yield return new LessThanTranslator();
            yield return new LessThanOrEqualsTranslator();
            yield return new GreaterThanTranslator(); 
            yield return new GreaterThanOrEqualsTranslator();
            yield return new EqualsTranslator(); 
            yield return new NotEqualsTranslator(); 
            yield return new ConvertTranslator();
            yield return new ConstantTranslator(); 
            yield return new NotTranslator();
            yield return new MemberAccessTranslator();
            yield return new ParameterTranslator();
            yield return new MemberInitTranslator(); 
            yield return new NewTranslator();
            yield return new AddTranslator(); 
            yield return new ConditionalTranslator(); 
            yield return new DivideTranslator();
            yield return new ModuloTranslator(); 
            yield return new SubtractTranslator();
            yield return new MultiplyTranslator();
            yield return new NegateTranslator();
            yield return new UnaryPlusTranslator(); 
            yield return new MethodCallTranslator();
            yield return new CoalesceTranslator(); 
            yield return new AsTranslator(); 
            yield return new IsTranslator();
            yield return new QuoteTranslator(); 
            yield return new AndTranslator();
            yield return new OrTranslator();
            yield return new ExclusiveOrTranslator();
            yield return new ExtensionTranslator(); 
            yield return new NewArrayInitTranslator();
            yield return new ListInitTranslator(); 
            yield return new NotSupportedTranslator( 
                ExpressionType.LeftShift,
                ExpressionType.RightShift, 
                ExpressionType.ArrayLength,
                ExpressionType.ArrayIndex,
                ExpressionType.Invoke,
                ExpressionType.Lambda, 
                ExpressionType.NewArrayBounds,
                ExpressionType.Power); 
        } 
        #endregion
 
        #region Properties
        private EdmItemCollection EdmItemCollection
        {
            get 
            {
                return (EdmItemCollection)_funcletizer.RootContext.MetadataWorkspace.GetItemCollection(DataSpace.CSpace, true); 
            } 
        }
        internal DbProviderManifest ProviderManifest 
        {
            get
            {
                return ((StoreItemCollection)_funcletizer.RootContext.MetadataWorkspace.GetItemCollection(DataSpace.SSpace)).StoreProviderManifest; 
            }
        } 
        internal System.Collections.ObjectModel.ReadOnlyCollection> GetParameters() 
        {
            if (null != _parameters) { return _parameters.AsReadOnly(); } 
            return null;
        }
        internal MergeOption? PropagatedMergeOption { get { return _mergeOption; } }
        internal Span PropagatedSpan { get { return _span; } } 
        internal Func RecompileRequired { get { return _recompileRequired; } }
        #endregion 
 
        #region Internal methods
        // Convert the LINQ expression to a CQT expression and (optional) Span information. 
        // Span information will only be present if ObjectQuery instances that specify Spans
        // are referenced from the LINQ expression in a manner consistent with the Span combination
        // rules, otherwise the Span for the CQT expression will be null.
        internal DbExpression Convert() 
        {
            DbExpression result = this.TranslateExpression(_expression); 
            if (!TryGetSpan(result, out _span)) 
            {
                _span = null; 
            }
            return result;
        }
 
        internal static bool CanFuncletizePropertyInfo(PropertyInfo propertyInfo)
        { 
            return MemberAccessTranslator.CanFuncletizePropertyInfo(propertyInfo); 
        }
        #endregion 

        #region Private Methods

        private void NotifyMergeOption(MergeOption mergeOption) 
        {
            if (!this._mergeOption.HasValue) 
            { 
                this._mergeOption = mergeOption;
            } 
        }

        // Requires: metadata must not be null.
        // 
        // Effects: adds initializer metadata to this query context.
        // 
        // Ensures that the given initializer metadata is valid within the current converter context. 
        // We do not allow two incompatible structures representing the same type within a query, e.g.,
        // 
        //      outer.Join(inner, o => new Foo { X = o.ID }, i => new Foo { Y = i.ID }, ...
        //
        // since this introduces a discrepancy between the CLR (where comparisons between Foo are aware
        // of both X and Y) and in ELinq (where comparisons are based on the row structure only), resulting 
        // in the following join predicates:
        // 
        //      Linq: foo1 == foo2 (which presumably amounts to foo1.X == foo2.X && foo1.Y == foo2.Y 
        //      ELinq: foo1.X == foo2.Y
        // 
        // Similar problems occur with set operations such as Union and Concat, where one of the initialization
        // patterns may be ignored.
        //
        // This method performs an overly strict check, requiring that all initializers for a given type 
        // are structurally equivalent.
        internal void ValidateInitializerMetadata(InitializerMetadata metadata) 
        { 
            Debug.Assert(null != metadata);
            InitializerMetadata existingMetadata; 
            if (_initializers != null && _initializers.TryGetValue(metadata.ClrType, out existingMetadata))
            {
                // Verify the initializers are compatible.
                if (!metadata.Equals(existingMetadata)) 
                {
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedHeterogeneousInitializers( 
                        ExpressionConverter.DescribeClrType(metadata.ClrType))); 
                }
            } 
            else
            {
                // Register the metadata so that subsequent initializers for this type can be verified.
                if (_initializers == null) 
                {
                    _initializers = new Dictionary(); 
                } 
                _initializers.Add(metadata.ClrType, metadata);
            } 
        }

        private void AddParameter(QueryParameterExpression queryParameter)
        { 
            if (null == _parameters)
            { 
                _parameters = new List>(); 
            }
            if (!_parameters.Select(p => p.Value).Contains(queryParameter)) 
            {
                ObjectParameter parameter = new ObjectParameter(queryParameter.ParameterReference.ParameterName, queryParameter.Type);
                _parameters.Add(new KeyValuePair(parameter, queryParameter));
            } 
        }
 
        private bool IsQueryRoot(Expression Expression) 
        {
            // 
            // An expression is the query root if it was the expression used
            // when constructing this converter.
            //
            return object.ReferenceEquals(_expression, Expression); 
        }
 
        #region Span Mapping maintenance methods 

        ///  
        /// Adds a new mapping from DbExpression => Span information for the specified expression,
        /// after first ensuring that the mapping dictionary has been instantiated.
        /// 
        /// The expression for which Span information should be added 
        /// 
        ///     The Span information, which may be null. 
        ///     If null, no attempt is made to update the dictionary of span mappings. 
        /// 
        /// The original  argument, to allow return AddSpanMapping(expression, span) scenarios 
        private DbExpression AddSpanMapping(DbExpression expression, Span span)
        {
            if (span != null)
            { 
                if (null == _spanMappings)
                { 
                    _spanMappings = new Dictionary(); 
                }
 
                _spanMappings[expression] = span;
            }

            return expression; 
        }
 
        ///  
        /// Attempts to retrieve Span information for the specified DbExpression.
        ///  
        /// The expression for which Span information should be retrieved.
        /// Will contain the Span information for the specified expression if it is present in the Span mapping dictionary.
        /// true if Span information was retrieved for the specified expression and  now contains this information; otherwise false.
        private bool TryGetSpan(DbExpression expression, out Span span) 
        {
            if (_spanMappings != null) 
            { 
                return _spanMappings.TryGetValue(expression, out span);
            } 

            span = null;
            return false;
        } 

        ///  
        /// Removes the Span mapping entry for the specified  expression, 
        /// and creates a new entry for the specified  expression that maps
        /// to the  expression's original Span information. If no Span 
        /// information is present for the specified  expression then no
        /// changes are made to the Span mapping dictionary.
        /// 
        /// The expression from which to take Span information 
        /// The expression to which the Span information should be applied
        private void ApplySpanMapping(DbExpression from, DbExpression to) 
        { 
            Span argumentSpan;
            if (TryGetSpan(from, out argumentSpan)) 
            {
                AddSpanMapping(to, argumentSpan);
            }
        } 

        ///  
        /// Unifies the Span information from the specified  and  
        /// expressions, and applies it to the specified  expression. Unification proceeds
        /// as follows: 
        /// - If neither  nor  have Span information, no changes are made
        /// - If one of  or  has Span information, that single Span information
        ///   entry is removed from the Span mapping dictionary and used to create a new entry that maps from the 
        ///   expression to the Span information. 
        /// - If both  and  have Span information, both entries are removed
        ///   from the Span mapping dictionary, a new Span is created that contains the union of the original Spans, and 
        ///   a new entry is added to the dictionary that maps from  expression to this new Span. 
        /// 
        /// The first expression argument 
        /// The second expression argument
        /// The result expression
        private void UnifySpanMappings(DbExpression left, DbExpression right, DbExpression to)
        { 
            Span leftSpan = null;
            Span rightSpan = null; 
 
            bool hasLeftSpan = TryGetSpan(left, out leftSpan);
            bool hasRightSpan = TryGetSpan(right, out rightSpan); 
            if (!hasLeftSpan && !hasRightSpan)
            {
                return;
            } 

            Debug.Assert(leftSpan != null || rightSpan != null, "Span mappings contain null?"); 
            AddSpanMapping(to, Span.CopyUnion(leftSpan, rightSpan)); 
        }
        #endregion 

        // The following methods correspond to query builder methods on ObjectQuery
        // and MUST be called by expression translators (instead of calling the equivalent
        // CommandTree.CreateXxExpression methods) to ensure that Span information flows 
        // correctly to the root of the Command Tree as it is constructed by converting
        // the LINQ expression tree. Each method correctly maintains a Span mapping (if required) 
        // for its resulting expression, based on the Span mappings of its argument expression(s). 

        private DbDistinctExpression Distinct(DbExpression argument) 
        {
            DbDistinctExpression retExpr = argument.Distinct();
            ApplySpanMapping(argument, retExpr);
            return retExpr; 
        }
 
        private DbExceptExpression Except(DbExpression left, DbExpression right) 
        {
            DbExceptExpression retExpr = left.Except(right); 
            ApplySpanMapping(left, retExpr);
            return retExpr;
        }
 
        private DbExpression Filter(DbExpressionBinding input, DbExpression predicate)
        { 
            DbExpression retExpr = OrderByLifter.Filter(input, predicate); 
            ApplySpanMapping(input.Expression, retExpr);
            return retExpr; 
        }

        private DbIntersectExpression Intersect(DbExpression left, DbExpression right)
        { 
            DbIntersectExpression retExpr = left.Intersect(right);
            UnifySpanMappings(left, right, retExpr); 
            return retExpr; 
        }
 
        private DbExpression Limit(DbExpression argument, DbExpression limit)
        {
            DbExpression retExpr = OrderByLifter.Limit(argument, limit);
            ApplySpanMapping(argument, retExpr); 
            return retExpr;
        } 
 
        private DbExpression OfType(DbExpression argument, TypeUsage ofType)
        { 
            DbExpression retExpr = OrderByLifter.OfType(argument, ofType);
            ApplySpanMapping(argument, retExpr);
            return retExpr;
        } 

        private DbExpression Project(DbExpressionBinding input, DbExpression projection) 
        { 
            DbExpression retExpr = OrderByLifter.Project(input, projection);
            // For identity projection only, the Span is preserved 
            if (projection.ExpressionKind == DbExpressionKind.VariableReference &&
               ((DbVariableReferenceExpression)projection).VariableName.Equals(input.VariableName, StringComparison.Ordinal))
            {
                ApplySpanMapping(input.Expression, retExpr); 
            }
            return retExpr; 
        } 

        private DbSortExpression Sort(DbExpressionBinding input, IList keys) 
        {
            DbSortExpression retExpr = input.Sort(keys);
            ApplySpanMapping(input.Expression, retExpr);
            return retExpr; 
        }
 
        private DbExpression Skip(DbExpressionBinding input, DbExpression skipCount) 
        {
            DbExpression retExpr = OrderByLifter.Skip(input, skipCount); 
            ApplySpanMapping(input.Expression, retExpr);
            return retExpr;
        }
 
        private DbUnionAllExpression UnionAll(DbExpression left, DbExpression right)
        { 
            DbUnionAllExpression retExpr = left.UnionAll(right); 
            UnifySpanMappings(left, right, retExpr);
            return retExpr; 
        }

        /// 
        /// Gets the target type for a CQT cast operation. 
        /// 
        /// Appropriate type usage, or null if this is a "no-op" 
        private TypeUsage GetCastTargetType(TypeUsage fromType, Type toClrType, Type fromClrType, bool preserveCastForDateTime) 
        {
            // An inlined ObjectQuery expression being cast to IQueryable for use in a sequence method is a no-op. 
            if(fromClrType != null &&
                fromClrType.IsGenericType && toClrType.IsGenericType &&
                fromClrType.GetGenericTypeDefinition() == typeof(ObjectQuery<>) &&
                (toClrType.GetGenericTypeDefinition() == typeof(IQueryable<>) || toClrType.GetGenericTypeDefinition() == typeof(IOrderedQueryable<>)) && 
                fromClrType.GetGenericArguments()[0] == toClrType.GetGenericArguments()[0])
            { 
                return null; 
            }
 
            // If the types are the same or the fromType is assignable to toType, return null
            // (indicating no cast is required)
            TypeUsage toType;
            if (TryGetValueLayerType(toClrType, out toType) && CanOmitCast(fromType, toType, preserveCastForDateTime)) 
            {
                return null; 
            } 

            // Check that the cast is supported and adjust the target type as necessary. 
            toType = ValidateAndAdjustCastTypes(toType, fromType, toClrType, fromClrType);

            return toType;
        } 

        ///  
        /// Check that the given cast specification is supported and if necessary adjust target type (for instance 
        /// add precision and scale for Integral -> Decimal casts)
        ///  
        private static TypeUsage ValidateAndAdjustCastTypes(TypeUsage toType, TypeUsage fromType, Type toClrType, Type fromClrType)
        {
            // only support primitives if real casting is involved
            if (toType == null || 
                !(TypeSemantics.IsPrimitiveType(toType)) ||
                !(TypeSemantics.IsPrimitiveType(fromType))) 
            { 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedCast(DescribeClrType(fromClrType), DescribeClrType(toClrType)));
            } 

            PrimitiveTypeKind fromTypeKind = ((PrimitiveType)fromType.EdmType).PrimitiveTypeKind;
            PrimitiveTypeKind toTypeKind = ((PrimitiveType)toType.EdmType).PrimitiveTypeKind;
 
            if (toTypeKind == PrimitiveTypeKind.Decimal)
            { 
                // Can't figure out the right precision and scale for decimal, so only accept integer types 
                switch (fromTypeKind)
                { 
                    case PrimitiveTypeKind.Byte:
                    case PrimitiveTypeKind.Int16:
                    case PrimitiveTypeKind.Int32:
                    case PrimitiveTypeKind.Int64: 
                    case PrimitiveTypeKind.SByte:
                        // adjust precision and scale to ensure sufficient width 
                        toType = TypeUsage.CreateDecimalTypeUsage((PrimitiveType)toType.EdmType, 19, 0); 
                        break;
                    default: 
                        throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedCastToDecimal);
                }
            }
 
            return toType;
        } 
 
        /// 
        /// Determines if an instance of fromType can be assigned to an instance of toType using 
        /// CLR semantics. in case of primitive type, it must rely on identity since unboxing primitive requires
        /// exact match. for nominal types, rely on subtyping.
        /// 
        private static bool CanOmitCast(TypeUsage fromType, TypeUsage toType, bool preserveCastForDateTime) 
        {
            bool isPrimitiveType = TypeSemantics.IsPrimitiveType(fromType); 
 
            //SQLBUDT #573573: This is to allow for a workaround on Katmai via explicit casting by the user.
            // The issue is that SqlServer's type Date maps to Edm.DateTime, same as SqlServer's DateTime and SmallDateTime. 
            // However the conversion is not possible for all values of Date.

            //Note: we could also call here TypeSemantics.IsPrimitiveType(TypeUsage type, PrimitiveTypeKind primitiveTypeKind),
            //  but that checks again whether the type is primitive 
            if (isPrimitiveType && preserveCastForDateTime && ((PrimitiveType)fromType.EdmType).PrimitiveTypeKind == PrimitiveTypeKind.DateTime)
            { 
                return false; 
            }
 
            if (TypeUsageEquals(fromType, toType))
            {
                return true;
            } 

            if (isPrimitiveType) 
            { 
                return fromType.EdmType.EdmEquals(toType.EdmType);
            } 

            return TypeSemantics.IsSubTypeOf(fromType, toType);
        }
 
        /// 
        /// Gets the target type for an Is or As expression. 
        ///  
        /// Input type in model metadata.
        /// Test or return type. 
        /// Type of operation; used in error reporting.
        /// Input type in CLR metadata.
        /// Appropriate target type usage.
        private TypeUsage GetIsOrAsTargetType(TypeUsage fromType, ExpressionType operationType, Type toClrType, Type fromClrType) 
        {
            Debug.Assert(operationType == ExpressionType.TypeAs || operationType == ExpressionType.TypeIs); 
 
            // Interpret all type information
            TypeUsage toType; 
            if (!this.TryGetValueLayerType(toClrType, out toType) ||
                (!TypeSemantics.IsEntityType(toType) &&
                 !TypeSemantics.IsComplexType(toType)))
            { 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedIsOrAs(operationType,
                    DescribeClrType(fromClrType), DescribeClrType(toClrType))); 
            } 

            return toType; 
        }

        // requires: inlineQuery is not null and inlineQuery is Entity-SQL query
        // effects: interprets the given query as an inline query in the current expression and unites 
        // the current query context with the context for the inline query. If the given query specifies
        // span information, then an entry is added to the span mapping dictionary from the CQT expression 
        // that is the root of the inline query, to the span information that was present in the inline 
        // query's Span property.
        private DbExpression TranslateInlineQueryOfT(ObjectQuery inlineQuery) 
        {
            if (!object.ReferenceEquals(_funcletizer.RootContext, inlineQuery.QueryState.ObjectContext))
            {
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedDifferentContexts); 
            }
 
            // Check if the inline query has been encountered so far. If so, we don't need to 
            // include its parameters again. We do however need to translate it to a new
            // DbExpression instance since the expressions may be tagged with span information 
            // and we don't want to mistakenly apply the directive to the wrong part of the query.
            if (null == _inlineEntitySqlQueries)
            {
                _inlineEntitySqlQueries = new HashSet(); 
            }
            bool isNewInlineQuery = _inlineEntitySqlQueries.Add(inlineQuery); 
 
            // The ObjectQuery should be Entity-SQL-based at this point. All other query types are currently
            // inlined. 
            EntitySqlQueryState esqlState = (EntitySqlQueryState)inlineQuery.QueryState;

            // We will produce the translated expression by parsing the Entity-SQL query text.
            DbExpression resultExpression = null; 

            // If we are not converting a compiled query, or the referenced Entity-SQL ObjectQuery 
            // does not have parameters (and so no parameter references can be in the parsed tree) 
            // then the Entity-SQL can be parsed directly using the conversion command tree.
            ObjectParameterCollection objectParameters = inlineQuery.QueryState.Parameters; 
            if (!_funcletizer.IsCompiledQuery ||
                objectParameters == null ||
                objectParameters.Count == 0)
            { 
                // Add parameters if they exist and we haven't yet encountered this inline query.
                if (isNewInlineQuery && objectParameters != null) 
                { 
                    // Copy the parameters into the aggregated parameter collection - this will result
                    // in an exception if any duplicate parameter names are encountered. 
                    if (this._parameters == null)
                    {
                        this._parameters = new List>();
                    } 
                    foreach (ObjectParameter prm in inlineQuery.QueryState.Parameters)
                    { 
                        this._parameters.Add(new KeyValuePair(prm.ShallowCopy(), null)); 
                    }
                } 

                resultExpression = esqlState.Parse();
            }
            else 
            {
                // We are converting a compiled query and parameters are present on the referenced ObjectQuery. 
                // The set of parameters available to a compiled query is fixed (so that adding/removing parameters 
                // to/from a referenced ObjectQuery does not invalidate the compiled query's execution plan), so the
                // referenced ObjectQuery will be fully inlined by replacing each parameter reference with a 
                // DbConstantExpression containing the value of the referenced parameter.
                resultExpression = esqlState.Parse();
                resultExpression = ParameterReferenceRemover.RemoveParameterReferences(resultExpression, objectParameters);
            } 

            return resultExpression; 
        } 

        private class ParameterReferenceRemover : DefaultExpressionVisitor 
        {
            internal static DbExpression RemoveParameterReferences(DbExpression expression, ObjectParameterCollection availableParameters)
            {
                ParameterReferenceRemover remover = new ParameterReferenceRemover(availableParameters); 
                return remover.VisitExpression(expression);
            } 
 
            private readonly ObjectParameterCollection objectParameters;
            private ParameterReferenceRemover(ObjectParameterCollection availableParams) 
                : base()
            {
                Debug.Assert(availableParams != null, "Parameter collection cannot be null");
 
                this.objectParameters = availableParams;
            } 
 
            public override DbExpression Visit(DbParameterReferenceExpression expression)
            { 
                if (this.objectParameters.Contains(expression.ParameterName))
                {
                    // A DbNullExpression is required for null values; DbConstantExpression otherwise.
                    ObjectParameter objParam = objectParameters[expression.ParameterName]; 
                    if (null == objParam.Value)
                    { 
                        return DbExpressionBuilder.Null(expression.ResultType); 
                    }
                    else 
                    {
                        // This will throw if the value is incompatible with the result type.
                        return DbExpressionBuilder.Constant(expression.ResultType, objParam.Value);
                    } 
                }
                return expression; 
            } 
        }
 
        // creates a CQT cast expression given the source and target CLR type
        private DbExpression CreateCastExpression(DbExpression source, Type toClrType, Type fromClrType)
        {
            // see if the source can be normalized as a set 
            DbExpression setSource = NormalizeSetSource(source);
            if (!Object.ReferenceEquals(source, setSource)) 
            { 
                // if the resulting cast is a no-op (no either kind is supported
                // for set sources), yield the source 
                if (null == GetCastTargetType(setSource.ResultType, toClrType, fromClrType, true))
                {
                    return source;
                } 
            }
 
            // try to find the appropriate target target for the cast 
            TypeUsage toType = GetCastTargetType(source.ResultType, toClrType, fromClrType, true);
            if (null == toType) 
            {
                // null indicates a no-op cast (from the perspective of the model)
                return source;
            } 

            return source.CastTo(toType); 
        } 

        // Utility translator method for lambda expressions. Given a lambda expression and its translated 
        // inputs, translates the lambda expression, assuming the input is a collection
        private DbExpression TranslateLambda(LambdaExpression lambda, DbExpression input, out DbExpressionBinding binding)
        {
            input = NormalizeSetSource(input); 

            // create binding context for this lambda expression 
            binding = input.Bind(); 

            return TranslateLambda(lambda, binding.Variable); 
        }

        // Utility translator method for lambda expressions that are part of group by. Given a lambda expression and its translated
        // inputs, translates the lambda expression, assuming the input needs to be used as a grouping input 
        private DbExpression TranslateLambda(LambdaExpression lambda, DbExpression input, out DbGroupExpressionBinding binding)
        { 
            input = NormalizeSetSource(input); 

            // create binding context for this lambda expression 
            binding = input.GroupBind();

            return TranslateLambda(lambda, binding.Variable);
        } 

        // Utility translator method for lambda expressions. Given a lambda expression and its translated 
        // inputs, translates the lambda expression 
        private DbExpression TranslateLambda(LambdaExpression lambda, DbExpression input)
        { 
            Binding scopeBinding = new Binding(lambda.Parameters[0], input);

            // push the binding scope
            _bindingContext.PushBindingScope(scopeBinding); 

            // translate expression within this binding scope 
            DbExpression result = TranslateExpression(lambda.Body); 

            // pop binding scope 
            _bindingContext.PopBindingScope();

            return result;
        } 

        // effects: unwraps any "structured" set sources such as IGrouping instances 
        // (which acts as both a set and a structure containing a property) 
        // NOTE: Changes made to this function might have to be applied to FunctionCallTranslator.NormalizeAllSetSources() too.
        private DbExpression NormalizeSetSource(DbExpression input) 
        {
            Debug.Assert(null != input);

            // determine if the lambda input is an IGrouping or EntityCollection that needs to be unwrapped 
            InitializerMetadata initializerMetadata;
            if (InitializerMetadata.TryGetInitializerMetadata(input.ResultType, out initializerMetadata)) 
            { 
                if (initializerMetadata.Kind == InitializerMetadataKind.Grouping)
                { 
                    // for group by, redirect the binding to the group (rather than the property)
                    input = input.Property(ExpressionConverter.GroupColumnName);
                }
                else if (initializerMetadata.Kind == InitializerMetadataKind.EntityCollection) 
                {
                    // for entity collection, redirect the binding to the children 
                    input = input.Property(ExpressionConverter.EntityCollectionElementsColumnName); 
                }
            } 
            return input;
        }

        // Given a method call expression, returns the given lambda argument (unwrapping quote or closure references where 
        // necessary)
        private LambdaExpression GetLambdaExpression(MethodCallExpression callExpression, int argumentOrdinal) 
        { 
            Expression argument = callExpression.Arguments[argumentOrdinal];
            return (LambdaExpression)GetLambdaExpression(argument); 
        }

        private Expression GetLambdaExpression(Expression argument)
        { 
            if (ExpressionType.Lambda == argument.NodeType)
            { 
                return argument; 
            }
            else if (ExpressionType.Quote == argument.NodeType) 
            {
                return GetLambdaExpression(((UnaryExpression)argument).Operand);
            }
 
            throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.UnexpectedLinqLambdaExpressionFormat);
        } 
 
        // Translate a LINQ expression acting as a set input to a CQT expression
        private DbExpression TranslateSet(Expression linq) 
        {
            return NormalizeSetSource(TranslateExpression(linq));
        }
 
        // Translate a LINQ expression to a CQT expression.
        private DbExpression TranslateExpression(Expression linq) 
        { 
            Debug.Assert(null != linq);
 
            DbExpression result;
            if (!_bindingContext.TryGetBoundExpression(linq, out result))
            {
                // translate to a CQT expression 
                Translator translator;
                if (s_translators.TryGetValue(linq.NodeType, out translator)) 
                { 
                    result = translator.Translate(this, linq);
                } 
                else
                {
                    throw EntityUtil.InternalError(EntityUtil.InternalErrorCode.UnknownLinqNodeType, -1,
                        linq.NodeType.ToString()); 
                }
            } 
            return result; 
        }
 
        // Cast expression to align types between CQT and eLINQ
        private DbExpression AlignTypes(DbExpression cqt, Type toClrType)
        {
            Type fromClrType = null; // not used in this code path 
            TypeUsage toType = GetCastTargetType(cqt.ResultType, toClrType, fromClrType, false);
            if (null != toType) 
            { 
                return cqt.CastTo(toType);
            } 
            else
            {
                return cqt;
            } 
        }
 
        // Determines whether the given type is supported for materialization 
        private void CheckInitializerType(Type type)
        { 
            // nominal types are not supported
            TypeUsage typeUsage;
            if (_funcletizer.RootContext.Perspective.TryGetType(type, out typeUsage))
            { 
                BuiltInTypeKind typeKind = typeUsage.EdmType.BuiltInTypeKind;
                if (BuiltInTypeKind.EntityType == typeKind || 
                    BuiltInTypeKind.ComplexType == typeKind) 
                {
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedNominalType( 
                        typeUsage.EdmType.FullName));
                }
            }
 
            // types implementing IEnumerable are not supported
            if (TypeSystem.IsSequenceType(type)) 
            { 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedEnumerableType(
                    DescribeClrType(type))); 
            }
        }

 
        // requires: Left and right are non-null.
        // effects: Determines if the given types are equivalent, ignoring facets. In 
        // the case of primitive types, consider types equivalent if their kinds are 
        // equivalent.
        // comments: This method is useful in cases where the type facets or specific 
        // store primitive type are not reliably known, e.g. when the EDM type is determined
        // from the CLR type
        private static bool TypeUsageEquals(TypeUsage left, TypeUsage right)
        { 
            Debug.Assert(null != left);
            Debug.Assert(null != right); 
            if (left.EdmType.EdmEquals(right.EdmType)) { return true; } 

            // compare element types for collection 
            if (BuiltInTypeKind.CollectionType == left.EdmType.BuiltInTypeKind &&
                BuiltInTypeKind.CollectionType == right.EdmType.BuiltInTypeKind)
            {
                return TypeUsageEquals( 
                    ((CollectionType)left.EdmType).TypeUsage,
                    ((CollectionType)right.EdmType).TypeUsage); 
            } 

            // special case for primitive types 
            if (BuiltInTypeKind.PrimitiveType == left.EdmType.BuiltInTypeKind &&
                BuiltInTypeKind.PrimitiveType == right.EdmType.BuiltInTypeKind)
            {
                // since LINQ expressions cannot indicate model types directly, we must 
                // consider types equivalent if they match on the given CLR equivalent
                // types (consider the Xml and String primitive types) 
                return ((PrimitiveType)left.EdmType).ClrEquivalentType.Equals( 
                    ((PrimitiveType)right.EdmType).ClrEquivalentType);
            } 

            return false;
        }
 
        private TypeUsage GetValueLayerType(Type linqType)
        { 
            TypeUsage type; 
            if (!TryGetValueLayerType(linqType, out type))
            { 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedType(linqType));
            }
            return type;
        } 

        // Determine C-Space equivalent type for linqType 
        private bool TryGetValueLayerType(Type linqType, out TypeUsage type) 
        {
            // Remove nullable 
            Type nonNullableType = TypeSystem.GetNonNullableType(linqType);

            // As an optimization, short-circuit when the provided type has a known type code.
            PrimitiveTypeKind? primitiveTypeKind = null; 
            switch (Type.GetTypeCode(nonNullableType))
            { 
                case TypeCode.Boolean: 
                    primitiveTypeKind = PrimitiveTypeKind.Boolean;
                    break; 
                case TypeCode.Byte:
                    primitiveTypeKind = PrimitiveTypeKind.Byte;
                    break;
                case TypeCode.DateTime: 
                    primitiveTypeKind = PrimitiveTypeKind.DateTime;
                    break; 
                case TypeCode.Decimal: 
                    primitiveTypeKind = PrimitiveTypeKind.Decimal;
                    break; 
                case TypeCode.Double:
                    primitiveTypeKind = PrimitiveTypeKind.Double;
                    break;
                case TypeCode.Int16: 
                    primitiveTypeKind = PrimitiveTypeKind.Int16;
                    break; 
                case TypeCode.Int32: 
                    primitiveTypeKind = PrimitiveTypeKind.Int32;
                    break; 
                case TypeCode.Int64:
                    primitiveTypeKind = PrimitiveTypeKind.Int64;
                    break;
                case TypeCode.SByte: 
                    primitiveTypeKind = PrimitiveTypeKind.SByte;
                    break; 
                case TypeCode.Single: 
                    primitiveTypeKind = PrimitiveTypeKind.Single;
                    break; 
                case TypeCode.String:
                    primitiveTypeKind = PrimitiveTypeKind.String;
                    break;
            } 

            if (primitiveTypeKind.HasValue) 
            { 
                type = EdmProviderManifest.Instance.GetCanonicalModelTypeUsage(primitiveTypeKind.Value);
                return true; 
            }

            // See if this is a collection type (if so, recursively resolve)
            Type elementType = TypeSystem.GetElementType(nonNullableType); 
            if (elementType != nonNullableType)
            { 
                TypeUsage elementTypeUsage; 
                if (TryGetValueLayerType(elementType, out elementTypeUsage))
                { 
                    type = TypeHelpers.CreateCollectionTypeUsage(elementTypeUsage);
                    return true;
                }
            } 

            // Ensure the metadata for this object type is loaded 
            _perspective.MetadataWorkspace.ImplicitLoadAssemblyForType(linqType, null); 

            // Retrieve type from map 
            return _perspective.TryGetTypeByName(
                nonNullableType.FullName,
                false, // ignoreCase
                out type); 
        }
 
        ///  
        /// Utility method validating type for comparison ops (isNull, equals, etc.).
        /// Only primitive types, entity types, and simple row types (no IGrouping/EntityCollection) are 
        /// supported.
        /// 
        private static void VerifyTypeSupportedForComparison(Type clrType, TypeUsage edmType, Stack memberPath)
        { 
            // NOTE: due to bug in null handling for complex types, complex types are currently not supported
            // for comparisons (see SQL BU 543956) 
            switch (edmType.EdmType.BuiltInTypeKind) 
            {
                case BuiltInTypeKind.PrimitiveType: 
                case BuiltInTypeKind.EntityType:
                case BuiltInTypeKind.RefType:
                    return;
                case BuiltInTypeKind.RowType: 
                    {
                        InitializerMetadata initializerMetadata; 
                        if (!InitializerMetadata.TryGetInitializerMetadata(edmType, out initializerMetadata) || 
                            initializerMetadata.Kind == InitializerMetadataKind.ProjectionInitializer ||
                            initializerMetadata.Kind == InitializerMetadataKind.ProjectionNew) 
                        {
                            VerifyRowTypeSupportedForComparison(clrType, (RowType)edmType.EdmType, memberPath);
                            return;
                        } 
                        break;
                    } 
                default: 
                    break;
            } 
            if (null == memberPath)
            {
                throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedComparison(DescribeClrType(clrType), Strings.ELinq_PrimitiveTypesSample));
            } 
            else
            { 
                // build up description of member path 
                StringBuilder memberPathDescription = new StringBuilder();
                foreach (EdmMember member in memberPath) 
                {
                    memberPathDescription.Append(Strings.ELinq_UnsupportedRowMemberComparison(member.Name));
                }
                memberPathDescription.Append(Strings.ELinq_UnsupportedRowTypeComparison(DescribeClrType(clrType))); 
                throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedRowComparison(memberPathDescription.ToString(), Strings.ELinq_PrimitiveTypesSample));
            } 
        } 

        private static void VerifyRowTypeSupportedForComparison(Type clrType, RowType rowType, Stack memberPath) 
        {
            foreach (EdmMember member in rowType.Properties)
            {
                if (null == memberPath) 
                {
                    memberPath = new Stack(); 
                } 
                memberPath.Push(member);
                VerifyTypeSupportedForComparison(clrType, member.TypeUsage, memberPath); 
                memberPath.Pop();
            }
        }
 
        /// 
        /// Describe type for exception message. 
        ///  
        internal static string DescribeClrType(Type clrType)
        { 
            string clrTypeName = clrType.Name;
            // Yes, this is a heuristic... just a best effort way of getting
            // a reasonable exception message
            if (IsCSharpGeneratedClass(clrTypeName, "DisplayClass") || 
                IsVBGeneratedClass(clrTypeName, "Closure"))
            { 
                return Strings.ELinq_ClosureType; 
            }
            if (IsCSharpGeneratedClass(clrTypeName, "AnonymousType") || 
                IsVBGeneratedClass(clrTypeName, "AnonymousType"))
            {
                return Strings.ELinq_AnonymousType;
            } 

            string returnName = string.Empty; 
            if (!String.IsNullOrEmpty(clrType.Namespace)) 
            {
                returnName += clrType.Namespace + "."; 
            }
            returnName += clrType.Name;
            return returnName;
        } 

        private static bool IsCSharpGeneratedClass(string typeName, string pattern) 
        { 
            return typeName.Contains("<>") && typeName.Contains("__") && typeName.Contains(pattern);
        } 

        private static bool IsVBGeneratedClass(string typeName, string pattern)
        {
            return typeName.Contains("_") && typeName.Contains("$") && typeName.Contains(pattern); 
        }
 
        ///  
        /// Creates an implementation of IsNull. Throws exception when operand type is not supported.
        ///  
        private DbExpression CreateIsNullExpression(DbExpression operand, Type operandClrType)
        {
            VerifyTypeSupportedForComparison(operandClrType, operand.ResultType, null);
            return operand.IsNull(); 
        }
 
        ///  
        /// Creates an implementation of equals using the given pattern. Throws exception when argument types
        /// are not supported for equals comparison. 
        /// 
        private DbExpression CreateEqualsExpression(DbExpression left, DbExpression right, EqualsPattern pattern, Type leftClrType, Type rightClrType)
        {
            VerifyTypeSupportedForComparison(leftClrType, left.ResultType, null); 
            VerifyTypeSupportedForComparison(rightClrType, right.ResultType, null);
 
            //For Ref Type comparison, check whether they refer to compatible Entity Types. 
            TypeUsage leftType = left.ResultType;
            TypeUsage rightType = right.ResultType; 
            if (leftType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType && rightType.EdmType.BuiltInTypeKind == BuiltInTypeKind.RefType)
            {
                TypeUsage commonType;
                if (!TypeSemantics.TryGetCommonType(leftType, rightType, out commonType)) 
                {
                    RefType leftRefType = left.ResultType.EdmType as RefType; 
                    RefType rightRefType = right.ResultType.EdmType as RefType; 
                    throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedRefComparison(leftRefType.ElementType.FullName, rightRefType.ElementType.FullName));
                } 
            }

            return RecursivelyRewriteEqualsExpression(left, right, pattern);
        } 
        private DbExpression RecursivelyRewriteEqualsExpression(DbExpression left, DbExpression right, EqualsPattern pattern)
        { 
            // check if either side is an initializer type 
            RowType leftType = left.ResultType.EdmType as RowType;
            RowType rightType = left.ResultType.EdmType as RowType; 

            if (null != leftType || null != rightType)
            {
                if ((null != leftType && null != rightType) && leftType.EdmEquals(rightType)) 
                {
                    DbExpression shreddedEquals = null; 
                    // if the types are the same, use struct equivalence semantics 
                    foreach (EdmProperty property in leftType.Properties)
                    { 
                        DbPropertyExpression leftElement = left.Property(property);
                        DbPropertyExpression rightElement = right.Property(property);
                        DbExpression elementsEquals = RecursivelyRewriteEqualsExpression(
                            leftElement, rightElement, pattern); 

                        // build up and expression 
                        if (null == shreddedEquals) { shreddedEquals = elementsEquals; } 
                        else { shreddedEquals = shreddedEquals.And(elementsEquals); }
                    } 
                    return shreddedEquals;
                }
                else
                { 
                    // if one or both sides is an initializer and the types are not the same,
                    // "equals" always evaluates to false 
                    return DbExpressionBuilder.False; 
                }
            } 
            else
            {
                return ImplementEquality(left, right, pattern);
            } 
        }
 
        // For comparisons, where the left and right side are nullable or not nullable, 
        // here are the (compositionally safe) null equality predicates:
        // -- x NOT NULL, y NULL 
        // x = y AND  NOT (y IS NULL)
        // -- x NULL, y NULL
        // (x = y AND  (NOT (x IS NULL OR y IS NULL))) OR (x IS NULL AND y IS NULL)
        // -- x NOT NULL, y NOT NULL 
        // x = y
        // -- x NULL, y NOT NULL 
        // x = y AND  NOT (x IS NULL) 
        private DbExpression ImplementEquality(DbExpression left, DbExpression right, EqualsPattern pattern)
        { 
            switch (left.ExpressionKind)
            {
                case DbExpressionKind.Constant:
                    switch (right.ExpressionKind) 
                    {
                        case DbExpressionKind.Constant: // constant EQ constant 
                            return left.Equal(right); 
                        case DbExpressionKind.Null: // null EQ constant --> false
                            return DbExpressionBuilder.False; 
                        default:
                            return ImplementEqualityConstantAndUnknown((System.Data.Common.CommandTrees.DbConstantExpression)left, right, pattern);
                    }
                case DbExpressionKind.Null: 
                    switch (right.ExpressionKind)
                    { 
                        case DbExpressionKind.Constant: // null EQ constant --> false 
                            return DbExpressionBuilder.False;
                        case DbExpressionKind.Null: // null EQ null --> true 
                            return DbExpressionBuilder.True;
                        default: // null EQ right --> right IS NULL
                            return right.IsNull();
                    } 
                default: // unknown
                    switch (right.ExpressionKind) 
                    { 
                        case DbExpressionKind.Constant:
                            return ImplementEqualityConstantAndUnknown((System.Data.Common.CommandTrees.DbConstantExpression)right, left, pattern); 
                        case DbExpressionKind.Null: //  left EQ null --> left IS NULL
                            return left.IsNull();
                        default:
                            return ImplementEqualityUnknownArguments(left, right, pattern); 
                    }
            } 
        } 

        // Generate an equality expression with one unknown operator and 
        private DbExpression ImplementEqualityConstantAndUnknown(
            System.Data.Common.CommandTrees.DbConstantExpression constant, DbExpression unknown, EqualsPattern pattern)
        {
            switch (pattern) 
            {
                case EqualsPattern.Store: 
                case EqualsPattern.PositiveNullEquality: 
                    // either both are non-null, or one is null and the predicate result is undefined
                    return constant.Equal(unknown); 
                default:
                    Debug.Fail("unknown pattern");
                    return null;
            } 
        }
 
        // Generate an equality expression where the values of the left and right operands are completely unknown 
        private DbExpression ImplementEqualityUnknownArguments(DbExpression left, DbExpression right, EqualsPattern pattern)
        { 
            switch (pattern)
            {
                case EqualsPattern.Store: // left EQ right
                    return left.Equal(right); 
                case EqualsPattern.PositiveNullEquality: // left EQ right OR (left IS NULL AND right IS NULL)
                    { 
                        return left.Equal(right).Or(left.IsNull().And(right.IsNull())); 
                    }
                default: 
                    Debug.Fail("unexpected pattern");
                    return null;
            }
        } 

        #endregion 
 
        #region Helper Methods Shared by Translators
        ///  
        /// Helper method for String.StartsWith, String.EndsWith and String.Contains
        ///
        /// object.Method(argument), where Method is one of String.StartsWith, String.EndsWith or
        /// String.Contains is translated into: 
        ///     1) If argument is a constant or parameter and the provider supports escaping:
        ///         object like ("%") + argument1 + ("%"), where argument1 is argument escaped by the provider 
        ///         and ("%") are appended on the begining/end depending on whether 
        ///         insertPercentAtStart/insertPercentAtEnd are specified
        ///     2) Otherwise: 
        ///           object.Method(argument) ->  defaultTranslator
        /// 
        /// 
        /// Should '%' be inserted at the begining of the pattern 
        /// Should '%' be inserted at the end of the pattern
        /// The delegate that provides the default translation 
        /// The translation 
        private DbExpression TranslateFunctionIntoLike(MethodCallExpression call, bool insertPercentAtStart, bool insertPercentAtEnd, Func defaultTranslator)
        { 
            char escapeChar;
            bool providerSupportsEscapingLikeArgument = this.ProviderManifest.SupportsEscapingLikeArgument(out escapeChar);
            bool useLikeTranslation = false;
            bool specifyEscape = true; 

            Expression patternExpression = call.Arguments[0]; 
            Expression inputExpression = call.Object; 

            QueryParameterExpression queryParameterExpression = patternExpression as QueryParameterExpression; 
            if (providerSupportsEscapingLikeArgument && (queryParameterExpression != null))
            {
                useLikeTranslation = true;
                bool specifyEscapeDummy; 
                patternExpression = queryParameterExpression.EscapeParameterForLike(input => PreparePattern(input, insertPercentAtStart, insertPercentAtEnd, out specifyEscapeDummy));
            } 
 
            DbExpression translatedPatternExpression = this.TranslateExpression(patternExpression);
            DbExpression translatedInputExpression = this.TranslateExpression(inputExpression); 

            if (providerSupportsEscapingLikeArgument && translatedPatternExpression.ExpressionKind == DbExpressionKind.Constant)
            {
                useLikeTranslation = true; 
                DbConstantExpression constantExpression = (DbConstantExpression)translatedPatternExpression;
 
                string preparedValue = PreparePattern((string)constantExpression.Value, insertPercentAtStart, insertPercentAtEnd, out specifyEscape); 
                Debug.Assert(preparedValue != null, "The prepared value should not be null when the input is non-null");
 
                //Note: the result type needs to be taken from the original expression, as the user may have specified Unicode/Non-Unicode
                translatedPatternExpression = DbExpressionBuilder.Constant(constantExpression.ResultType, preparedValue);
            }
 
            DbExpression result;
            if (useLikeTranslation) 
            { 
                if (specifyEscape)
                { 
                    result = DbExpressionBuilder.Like(translatedInputExpression, translatedPatternExpression, DbExpressionBuilder.Constant(new String(new char[] { escapeChar })));
                }
                else
                { 
                    result = DbExpressionBuilder.Like(translatedInputExpression, translatedPatternExpression);
                } 
            } 
            else
            { 
                result = defaultTranslator(this, call, translatedPatternExpression, translatedInputExpression);
            }

            return result; 
        }
 
        ///  
        /// Prepare the given input patternValue into a pattern to be used in a LIKE expression by
        /// first escaping it by the provider and then appending "%" and the beginging/end depending 
        /// on whether insertPercentAtStart/insertPercentAtEnd is specified.
        /// 
        private string PreparePattern(string patternValue, bool insertPercentAtStart, bool insertPercentAtEnd, out bool specifyEscape)
        { 
            // Dev10 #800466: The pattern value if originating from a parameter value could be null
            if (patternValue == null) 
            { 
                specifyEscape = false;
                return null; 
            }

            string escapedPatternValue = this.ProviderManifest.EscapeLikeArgument(patternValue);
 
            if (escapedPatternValue == null)
            { 
                throw EntityUtil.ProviderIncompatible(System.Data.Entity.Strings.ProviderEscapeLikeArgumentReturnedNull); 
            }
 
            specifyEscape = patternValue != escapedPatternValue;

            System.Text.StringBuilder patternBuilder = new System.Text.StringBuilder();
            if (insertPercentAtStart) 
            {
                patternBuilder.Append("%"); 
            } 
            patternBuilder.Append(escapedPatternValue);
            if (insertPercentAtEnd) 
            {
                patternBuilder.Append("%");
            }
 
            return  patternBuilder.ToString();
        } 
 
        /// 
        ///  Translates the arguments into DbExpressions 
        ///   and creates a canonical function with the given functionName and these arguments
        /// 
        /// Should represent a non-aggregate canonical function
        /// Passed only for error handling purposes 
        /// 
        ///  
        private DbFunctionExpression TranslateIntoCanonicalFunction(string functionName, Expression Expression, params Expression[] linqArguments) 
        {
            DbExpression[] translatedArguments = new DbExpression[linqArguments.Length]; 
            for (int i = 0; i < linqArguments.Length; i++)
            {
                translatedArguments[i] = TranslateExpression(linqArguments[i]);
            } 
            return CreateCanonicalFunction(functionName, Expression, translatedArguments);
        } 
 
        /// 
        /// Creates a canonical function with the given name and the given arguments 
        /// 
        /// Should represent a non-aggregate canonical function
        /// Passed only for error handling purposes
        ///  
        /// 
        private DbFunctionExpression CreateCanonicalFunction(string functionName, Expression Expression, params DbExpression[] translatedArguments) 
        { 
            List translatedArgumentTypes = new List(translatedArguments.Length);
            foreach (DbExpression translatedArgument in translatedArguments) 
            {
                translatedArgumentTypes.Add(translatedArgument.ResultType);
            }
            EdmFunction function = FindCanonicalFunction(functionName, translatedArgumentTypes, false /* isGroupAggregateFunction */, Expression); 
            return function.Invoke(translatedArguments);
        } 
 
        /// 
        /// Finds a canonical function with the given functionName and argumentTypes 
        /// 
        /// 
        /// 
        ///  
        /// 
        ///  
        private EdmFunction FindCanonicalFunction(string functionName, IList argumentTypes, bool isGroupAggregateFunction, Expression Expression) 
        {
            return FindFunction(EdmNamespaceName, functionName, argumentTypes, isGroupAggregateFunction, Expression); 
        }

        /// 
        /// Finds a function with the given namespaceName, functionName and argumentTypes 
        /// 
        ///  
        ///  
        /// 
        ///  
        /// 
        /// 
        private EdmFunction FindFunction(string namespaceName, string functionName, IList argumentTypes, bool isGroupAggregateFunction, Expression Expression)
        { 
            // find the function
            IList candidateFunctions; 
            if (!_perspective.TryGetFunctionByName(string.Join(".", new[] {namespaceName, functionName}), false /* ignore case */, out candidateFunctions)) 
            {
                ThrowUnresolvableFunction(Expression); 
            }

            Debug.Assert(null != candidateFunctions && candidateFunctions.Count > 0, "provider functions must not be null or empty");
 
            bool isAmbiguous;
            EdmFunction function = FunctionOverloadResolver.ResolveFunctionOverloads(candidateFunctions, argumentTypes, isGroupAggregateFunction, out isAmbiguous); 
            if (isAmbiguous || null == function) 
            {
                ThrowUnresolvableFunctionOverload(Expression, isAmbiguous); 
            }
            return function;
        }
 
        /// 
        /// Helper method for FindFunction 
        ///  
        /// 
        private static void ThrowUnresolvableFunction(Expression Expression) 
        {
            if (Expression.NodeType == ExpressionType.Call)
            {
                MethodInfo methodInfo = ((MethodCallExpression)Expression).Method; 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnresolvableFunctionForMethod(methodInfo, methodInfo.DeclaringType));
            } 
            else if (Expression.NodeType == ExpressionType.MemberAccess) 
            {
                string memberName; 
                Type memberType;
                MemberInfo memberInfo = TypeSystem.PropertyOrField(((MemberExpression)Expression).Member, out memberName, out memberType);
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnresolvableFunctionForMember(memberInfo, memberInfo.DeclaringType));
            } 
            throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnresolvableFunctionForExpression(Expression.NodeType));
        } 
 
        /// 
        /// Helper method for FindCanonicalFunction 
        /// 
        /// 
        private static void ThrowUnresolvableFunctionOverload(Expression Expression, bool isAmbiguous)
        { 
            if (Expression.NodeType == ExpressionType.Call)
            { 
                MethodInfo methodInfo = ((MethodCallExpression)Expression).Method; 
                if (isAmbiguous)
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnresolvableFunctionForMethodAmbiguousMatch(methodInfo, methodInfo.DeclaringType));
                }
                else
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnresolvableFunctionForMethodNotFound(methodInfo, methodInfo.DeclaringType));
                } 
            } 
            else if (Expression.NodeType == ExpressionType.MemberAccess)
            { 
                string memberName;
                Type memberType;
                MemberInfo memberInfo = TypeSystem.PropertyOrField(((MemberExpression)Expression).Member, out memberName, out memberType);
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnresolvableStoreFunctionForMember(memberInfo, memberInfo.DeclaringType)); 
            }
            throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnresolvableStoreFunctionForExpression(Expression.NodeType)); 
        } 

        private DbNewInstanceExpression CreateNewRowExpression(List> columns, InitializerMetadata initializerMetadata) 
        {
            List propertyValues = new List(columns.Count);
            List properties = new List(columns.Count);
            for (int i = 0; i < columns.Count; i++) 
            {
                var column = columns[i]; 
                propertyValues.Add(column.Value); 
                properties.Add(new EdmProperty(column.Key, column.Value.ResultType));
            } 
            RowType rowType = new RowType(properties, initializerMetadata);
            TypeUsage typeUsage = TypeUsage.Create(rowType);
            return typeUsage.New(propertyValues);
        } 

        #endregion 
 
        #region Private enums
        // Describes different implementation pattern for equality comparisons. 
        // For all patterns, if one side of the expression is a constant null, converts to an IS NULL
        // expression (or resolves to 'true' or 'false' if some constraint is known for the other side).
        //
        // If neither side is a constant null, the semantics differ: 
        //
        // Store: left EQ right 
        // NullEquality: left EQ right OR (left IS NULL AND right IS NULL) 
        // PositiveEquality: left EQ right
        // 
        // In the actual implementation (see ImplementEquality), optimizations exist if one or the other
        // side is known not to be null.
        private enum EqualsPattern
        { 
            Store, // defer to store
            PositiveNullEquality, // null == null is 'true', null == (not null) us undefined 
        } 
        #endregion
    } 
}

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