Translator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / ndp / fx / src / DataEntity / System / Data / Objects / ELinq / Translator.cs / 3 / Translator.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System.Data.Common.CommandTrees;
using System.Collections.Generic; 
using CqtExpression = System.Data.Common.CommandTrees.DbExpression;
using LinqExpression = System.Linq.Expressions.Expression;
using System.Diagnostics;
using System.Data.Metadata.Edm; 
using System.Linq.Expressions;
using System.Reflection; 
using System.Data.Objects.DataClasses; 
using System.Globalization;
using System.Data.Entity; 
namespace System.Data.Objects.ELinq
{
    internal sealed partial class ExpressionConverter
    { 
        // Base class supporting the translation of LINQ node type(s) given a LINQ expression
        // of that type, and the "parent" translation context (the ExpressionConverter processor) 
        private abstract class Translator 
        {
            private readonly ExpressionType[] _nodeTypes; 
            protected Translator(params ExpressionType[] nodeTypes)
            {
                _nodeTypes = nodeTypes;
            } 
            // Gets LINQ node types this translator should be registed to process.
            internal IEnumerable NodeTypes { get { return _nodeTypes; } } 
            internal abstract CqtExpression Translate(ExpressionConverter parent, LinqExpression linq); 
            public override string ToString()
            { 
                return this.GetType().Name;
            }
        }
 
        #region Misc
        // Typed version of Translator 
        private abstract class TypedTranslator : Translator 
            where T_Linq : LinqExpression
        { 
            protected TypedTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes) { }
            internal override CqtExpression Translate(ExpressionConverter parent, LinqExpression linq)
            { 
                return TypedTranslate(parent, (T_Linq)linq);
            } 
            protected abstract CqtExpression TypedTranslate(ExpressionConverter parent, T_Linq linq); 
        }
        private sealed class ConstantTranslator 
            : TypedTranslator
        {
            internal ConstantTranslator()
                : base(ExpressionType.Constant) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.ConstantExpression linq)
            { 
                ObjectQuery queryOfT = linq.Value as ObjectQuery; 
                if (null != queryOfT)
                { 
                    return parent.TranslateInlineQueryOfT(queryOfT);
                }

                bool isNullValue = null == linq.Value; 

                // Remove facet information: null instances do not constrain type facets (e.g. a null string does not restrict 
                // "length" in compatibility checks) 
                TypeUsage type;
                bool typeSupported = false; 
                if (parent.TryGetValueLayerType(linq.Type, out type))
                {
                    // For constant values, support only primitive type (this is all that is supported by CQTs)
                    // For null types, also allow EntityType. Although other types claim to be supported, they 
                    // don't work (e.g. complex type, see SQL BU 543956)
                    if (type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType || 
                        (isNullValue && type.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType)) 
                    {
                        typeSupported = true; 
                    }
                }

                if (!typeSupported) 
                {
                    throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedConstant(DescribeClrType(linq.Type), Strings.ELinq_PrimitiveTypesSample)); 
                } 

                // create a constant or null expression depending on value 
                if (isNullValue)
                {
                    return parent._commandTree.CreateNullExpression(type);
                } 
                else
                { 
                    return parent._commandTree.CreateConstantExpression(linq.Value, type); 
                }
            } 
        }
        private sealed class MemberAccessTranslator
            : TypedTranslator
        { 
            internal MemberAccessTranslator()
                : base(ExpressionType.MemberAccess) { } 
            // attempt to translate the member access to a "regular" property, a navigation property, or a calculated 
            // property
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, MemberExpression linq) 
            {
                CqtExpression propertyExpression;
                string memberName;
                Type memberType; 
                MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Member, out memberName, out memberType);
 
                // note: we check for "regular" properties last, since the other two flavors derive 
                // from this one
                if (linq.Expression != null) 
                {
                    CqtExpression instance = parent.TranslateExpression(linq.Expression);
                    if (TryResolveAsProperty(parent, memberInfo,
                        instance.ResultType, instance, out propertyExpression)) 
                    {
                        return propertyExpression; 
                    } 
                }
 
                if (memberInfo.MemberType == MemberTypes.Property)
                {
                    // Check whether it is one of the special proeperties that we know how to translate
                    PropertyTranslator propertyTranslator; 
                    if (TryGetTranslator((PropertyInfo)memberInfo, out propertyTranslator))
                    { 
                        return propertyTranslator.Translate(parent, linq); 
                    }
                } 

                // no other property types are supported by LINQ over entities
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnrecognizedMember(linq.Member.Name));
            } 

            #region Static members and initializers 
            private static readonly Dictionary s_propertyTranslators; 
            private static bool s_vbPropertiesInitialized;
            private static readonly object s_vbInitializerLock = new object(); 

            static MemberAccessTranslator()
            {
                // initialize translators for specific properties 
                s_propertyTranslators = new Dictionary();
                foreach (PropertyTranslator translator in GetPropertyTranslators()) 
                { 
                    foreach (PropertyInfo property in translator.Properties)
                    { 
                        s_propertyTranslators.Add(property, translator);
                    }
                }
            } 

            ///  
            /// Tries to get a translator for the given property info. 
            /// If the given property info corresponds to a Visual Basic property,
            /// it also initializes the Visual Basic translators if they have not been initialized 
            /// 
            /// 
            /// 
            ///  
            private static bool TryGetTranslator(PropertyInfo propertyInfo, out PropertyTranslator propertyTranslator)
            { 
                //If the type is generic, we try to match the generic property 
                if (propertyInfo.DeclaringType.IsGenericType)
                { 
                    try
                    {
                        propertyInfo = propertyInfo.DeclaringType.GetGenericTypeDefinition().GetProperty(propertyInfo.Name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
                    } 
                    catch (AmbiguousMatchException)
                    { 
                        propertyTranslator = null; 
                        return false;
                    } 
                    if (propertyInfo == null)
                    {
                        propertyTranslator = null;
                        return false; 
                    }
                } 
 
                if (s_propertyTranslators.TryGetValue(propertyInfo, out propertyTranslator))
                { 
                    return true;
                }

                // check if this is the visual basic assembly 
                if (s_visualBasicAssemblyFullName == propertyInfo.DeclaringType.Assembly.FullName)
                { 
                    lock (s_vbInitializerLock) 
                    {
                        if (!s_vbPropertiesInitialized) 
                        {
                            InitializeVBProperties(propertyInfo.DeclaringType.Assembly);
                            s_vbPropertiesInitialized = true;
                        } 
                        // try again
                        return s_propertyTranslators.TryGetValue(propertyInfo, out propertyTranslator); 
                    } 
                }
                propertyTranslator = null; 
                return false;
            }

            // Determines if the given property can be resolved as a standard or navigation property. 
            private static bool TryResolveAsProperty(ExpressionConverter parent,
                MemberInfo clrMember, TypeUsage definingType, CqtExpression instance, out CqtExpression propertyExpression) 
            { 
                // retrieve members directly from row types, which are not mapped between O and C
                RowType rowType = definingType.EdmType as RowType; 
                string name = clrMember.Name;

                if (null != rowType)
                { 
                    EdmMember member;
                    if (rowType.Members.TryGetValue(name, false, out member)) 
                    { 
                        propertyExpression = parent._commandTree.CreatePropertyExpression(name, instance);
                        return true; 
                    }

                    propertyExpression = null;
                    return false; 
                }
 
                // for non-row structural types, map from the O to the C layer using the perspective 
                StructuralType structuralType = definingType.EdmType as StructuralType;
                if (null != structuralType) 
                {
                    EdmMember member = null;
                    if (parent._typeResolver.Perspective.TryGetMember(structuralType, name, false, out member))
                    { 
                        if (null != member)
                        { 
                            if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty) 
                            {
                                NavigationProperty navProp = (NavigationProperty)member; 
                                propertyExpression = TranslateNavigationProperty(parent, clrMember, instance, navProp);
                                return true;
                            }
                            else 
                            {
                                // if we're accessing a key member of a navigation, collapse the structure instance 
                                // to the key reference. 
                                instance = NormalizeInstanceForReference(parent, instance, member);
                                propertyExpression = parent._commandTree.CreatePropertyExpression(name, instance); 
                                return true;
                            }

                        } 
                    }
                } 
 
                // try to unwrap GroupBy "Key" member
                if (name == ExpressionConverter.KeyColumnName) 
                {
                    // see if we can "unwrap" the current instance
                    if (DbExpressionKind.Property == instance.ExpressionKind)
                    { 
                        DbPropertyExpression property = (DbPropertyExpression)instance;
                        InitializerMetadata initializerMetadata; 
 
                        // if we're dealing with the "Group" property of a GroupBy projection, we know how to unwrap
                        // it 
                        if (property.Property.Name == ExpressionConverter.GroupColumnName && // only know how to unwrap the group
                            InitializerMetadata.TryGetInitializerMetadata(property.Instance.ResultType, out initializerMetadata) &&
                            initializerMetadata.Kind == InitializerMetadataKind.Grouping)
                        { 
                            propertyExpression = parent._commandTree.CreatePropertyExpression(ExpressionConverter.KeyColumnName,
                                property.Instance); 
                            return true; 
                        }
                    } 
                }

                propertyExpression = null;
                return false; 
            }
 
            ///  
            /// We simplify the property instance where the user is accessing a key member of
            /// a reference navigation. The instance becomes simply the reference key in such 
            /// cases.
            ///
            /// For instance, product.Category.CategoryID becomes Ref(product.Category).CategoryID,
            /// which gives us a chance of optimizing the query (using foreign keys rather than joins) 
            /// 
            /// Conversion context. 
            /// Instance from which we're accessing member. 
            /// Member we're accessing.
            /// 'Simplified' instance. If the member is a key and the instance is a navigation 
            /// the returned instance is a reference navigation rather than the full entity.
            private static CqtExpression NormalizeInstanceForReference(ExpressionConverter parent, CqtExpression instance, EdmMember member)
            {
                EdmType instanceType = instance.ResultType.EdmType; 

                if (instanceType.BuiltInTypeKind == BuiltInTypeKind.EntityType) 
                { 
                    EntityType entityType = (EntityType)instanceType;
                    if (entityType.KeyMembers.Contains(member) && instance.ExpressionKind == DbExpressionKind.Property) 
                    {
                        DbPropertyExpression propertyExpression = (DbPropertyExpression)instance;
                        if (propertyExpression.Property.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty)
                        { 
                            // modify the property expression so that it merely retrieves the reference
                            // not the entire entity 
                            NavigationProperty navigationProperty = (NavigationProperty)propertyExpression.Property; 

                            DbExpression navigationSource = parent._commandTree.CreateEntityRefExpression(propertyExpression.Instance); 
                            DbExpression navigationExpression = parent._commandTree.CreateRelationshipNavigationExpression(
                                navigationProperty.FromEndMember,
                                navigationProperty.ToEndMember,
                                navigationSource); 
                            instance = parent._commandTree.CreateRefKeyExpression(navigationExpression);
                        } 
                    } 
                }
                return instance; 
            }

            private static CqtExpression TranslateNavigationProperty(ExpressionConverter parent, MemberInfo clrMember, CqtExpression instance, NavigationProperty navProp)
            { 
                CqtExpression propertyExpression;
                propertyExpression = parent._commandTree.CreatePropertyExpression(navProp, instance); 
 
                // for EntityCollection navigations, wrap in "grouping" where the key is the parent
                // entity and the group contains the child entities 
                if (BuiltInTypeKind.CollectionType == propertyExpression.ResultType.EdmType.BuiltInTypeKind)
                {
                    List> collectionColumns =
                        new List>(2); 
                    collectionColumns.Add(new KeyValuePair(
                        ExpressionConverter.EntityCollectionOwnerColumnName, instance)); 
                    collectionColumns.Add(new KeyValuePair( 
                        ExpressionConverter.EntityCollectionElementsColumnName, propertyExpression));
                    propertyExpression = parent.CreateNewRowExpression(collectionColumns, 
                        InitializerMetadata.CreateEntityCollectionInitializer(parent.EdmItemCollection, ((PropertyInfo)clrMember).PropertyType, navProp));
                }
                return propertyExpression;
            } 

            private static void InitializeVBProperties(Assembly vbAssembly) 
            { 
                Debug.Assert(!s_vbPropertiesInitialized);
                foreach (PropertyTranslator translator in GetVisualBasicPropertyTranslators(vbAssembly)) 
                {
                    foreach (PropertyInfo property in translator.Properties)
                    {
                        s_propertyTranslators.Add(property, translator); 
                    }
                } 
            } 

            private static IEnumerable GetVisualBasicPropertyTranslators(Assembly vbAssembly) 
            {
                yield return new VBDateAndTimeNowTranslator(vbAssembly);
            }
 
            private static IEnumerable GetPropertyTranslators()
            { 
                yield return new DefaultCanonicalFunctionPropertyTranslator(); 
                yield return new RenameCanonicalFunctionPropertyTranslator();
                yield return new EntityCollectionCountTranslator(); 
                yield return new NullableHasValueTranslator();
                yield return new NullableValueTranslator();
            }
 
            /// 
            /// Checks whether the given property info can be translated into a canonical function. 
            /// This method is used to determine whether client side evaluation should be done, 
            /// if the property can be evaluated in the store, it is not being evaluated on the client
            ///  
            /// 
            /// 
            internal static bool CanTranslatePropertyInfo(PropertyInfo propertyInfo)
            { 
                PropertyTranslator propertyTranslator;
                return TryGetTranslator(propertyInfo, out propertyTranslator); 
            } 
            #endregion
 
            #region Property Translators
            private abstract class PropertyTranslator
            {
                private readonly IEnumerable _properties; 
                protected PropertyTranslator(params PropertyInfo[] properties) { _properties = properties; }
                protected PropertyTranslator(IEnumerable properties) { _properties = properties; } 
                internal IEnumerable Properties { get { return _properties; } } 
                internal abstract CqtExpression Translate(ExpressionConverter parent, MemberExpression call);
                public override string ToString() 
                {
                    return GetType().Name;
                }
            } 

            private sealed class DefaultCanonicalFunctionPropertyTranslator : PropertyTranslator 
            { 
                internal DefaultCanonicalFunctionPropertyTranslator()
                    : base(GetProperties()) { } 

                private static IEnumerable GetProperties()
                {
                    yield return typeof(String).GetProperty("Length", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance);

                    yield return typeof(DateTimeOffset).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance);
                }

                // Default translator for method calls into canonical functions. 
                // Translation:
                //      object.PropertyName  -> PropertyName(object) 
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    return parent.TranslateIntoCanonicalFunction(call.Member.Name, call, call.Expression); 
                }
            }

            private sealed class RenameCanonicalFunctionPropertyTranslator : PropertyTranslator 
            {
                private static readonly Dictionary s_propertyRenameMap = new Dictionary(2); 
 
                internal RenameCanonicalFunctionPropertyTranslator()
                    : base(GetProperties()) { } 

                private static IEnumerable GetProperties()
                {
                    yield return GetProperty(typeof(DateTime), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTime); 
                    yield return GetProperty(typeof(DateTime), "UtcNow", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentUtcDateTime);
                    yield return GetProperty(typeof(DateTimeOffset), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTimeOffset); 
 
                    yield return GetProperty(typeof(TimeSpan), "Hours", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Hour);
                    yield return GetProperty(typeof(TimeSpan), "Minutes", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Minute); 
                    yield return GetProperty(typeof(TimeSpan), "Seconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Second);
                    yield return GetProperty(typeof(TimeSpan), "Milliseconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Millisecond);
                }
 
                private static PropertyInfo GetProperty(Type declaringType, string propertyName, BindingFlags bindingFlages, string canonicalFunctionName)
                { 
                    PropertyInfo propertyInfo = declaringType.GetProperty(propertyName, bindingFlages); 
                    s_propertyRenameMap.Add(propertyInfo, canonicalFunctionName);
                    return propertyInfo; 
                }

                // Translator for static properties into canonical functions when there is a corresponding
                // canonical function but with a differnet name 
                // Translation:
                //      object.PropertyName  -> CanonicalFunctionName(object) 
                //      Type.PropertyName  -> CanonicalFunctionName() 
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    PropertyInfo property = (PropertyInfo)call.Member;
                    String canonicalFunctionName = s_propertyRenameMap[property];
                    CqtExpression result;
                    if (call.Expression == null) 
                    {
                        result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call); 
                    } 
                    else
                    { 
                        result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call, call.Expression);
                    }
                    return result;
                } 
            }
 
            private sealed class VBDateAndTimeNowTranslator : PropertyTranslator 
            {
                private const string s_dateAndTimeTypeFullName = "Microsoft.VisualBasic.DateAndTime"; 

                internal VBDateAndTimeNowTranslator(Assembly vbAssembly)
                    : base(GetProperty(vbAssembly)) { }
 
                private static PropertyInfo GetProperty(Assembly vbAssembly)
                { 
                    return vbAssembly.GetType(s_dateAndTimeTypeFullName).GetProperty("Now", BindingFlags.Public | BindingFlags.Static); 
                }
 
                // Translation:
                //      Now -> GetDate()
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    return parent.TranslateIntoCanonicalFunction(ExpressionConverter.CurrentDateTime, call);
                } 
            } 

            private sealed class EntityCollectionCountTranslator : PropertyTranslator 
            {
                internal EntityCollectionCountTranslator()
                    : base(GetProperty()) { }
 
                private static PropertyInfo GetProperty()
                { 
                    return typeof(EntityCollection<>).GetProperty(ExpressionConverter.s_entityCollectionCountPropertyName, BindingFlags.Public | BindingFlags.Instance); 
                }
 
                // Translation:
                //      EntityCollection.Count -> Count()
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    // retranslate as a Count() aggregate, since the name collision prevents us
                    // from calling the method directly in VB and C# 
                    MethodInfo countMethod; 
                    ReflectionUtil.TryLookupMethod(SequenceMethod.Count, out countMethod);
                    Debug.Assert(null != countMethod, "Count() must exist"); 
                    countMethod = countMethod.MakeGenericMethod(call.Member.DeclaringType.GetGenericArguments());
                    LinqExpression countCall = LinqExpression.Call(countMethod, call.Expression);
                    return parent.TranslateExpression(countCall);
                } 
            }
 
            private sealed class NullableHasValueTranslator : PropertyTranslator 
            {
                internal NullableHasValueTranslator() 
                    : base(GetProperty()) { }

                private static PropertyInfo GetProperty()
                { 
                    return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableHasValuePropertyName, BindingFlags.Public | BindingFlags.Instance);
                } 
 
                // Translation:
                //      Nullable.HasValue -> Not(IsNull(arg)) 
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                {
                    CqtExpression argument = parent.TranslateExpression(call.Expression);
                    Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type"); 
                    return parent._commandTree.CreateNotExpression(parent.CreateIsNullExpression(argument, call.Expression.Type));
                } 
            } 

            private sealed class NullableValueTranslator : PropertyTranslator 
            {
                internal NullableValueTranslator()
                    : base(GetProperty()) { }
 
                private static PropertyInfo GetProperty()
                { 
                    return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableValuePropertyName, BindingFlags.Public | BindingFlags.Instance); 
                }
 
                // Translation:
                //      Nullable.Value -> arg
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    CqtExpression argument = parent.TranslateExpression(call.Expression);
                    Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type"); 
                    return argument; 
                }
            } 
            #endregion
        }
        private sealed class ParameterTranslator
            : TypedTranslator 
        {
            internal ParameterTranslator() 
                : base(ExpressionType.Parameter) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, ParameterExpression linq)
            { 
                // Bindings should be intercepted before we get to this point (in ExpressionConverter.TranslateExpression)
                if (parent._bindingContext.IsRootContextParameter(linq))
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnsupportedUseOfContextParameter(linq.Name)); 
                }
                else 
                { 
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnboundParameterExpression(linq.Name));
                } 
            }
        }
        private sealed class NewTranslator
            : TypedTranslator 
        {
            internal NewTranslator() 
                : base(ExpressionType.New) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, NewExpression linq)
            { 
                int memberCount = null == linq.Members ? 0 : linq.Members.Count;

                if (null == linq.Constructor ||
                    linq.Arguments.Count != memberCount) 
                {
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor); 
                } 

                parent.CheckInitializerType(linq.Type); 

                List> recordColumns =
                    new List>(memberCount + 1);
 
                HashSet memberNames = new HashSet(StringComparer.Ordinal);
                for (int i = 0; i < memberCount; i++) 
                { 
                    string memberName;
                    Type memberType; 
                    MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Members[i], out memberName, out memberType);
                    CqtExpression memberValue = parent.TranslateExpression(linq.Arguments[i]);
                    memberNames.Add(memberName);
                    recordColumns.Add(new KeyValuePair(memberName, memberValue)); 
                }
 
                InitializerMetadata initializerMetadata; 
                if (0 == memberCount)
                { 
                    // add a sentinel column because CQTs do not accept empty row types
                    recordColumns.Add(new KeyValuePair(KeyColumnName, parent._commandTree.CreateTrueExpression()));
                    initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq);
                } 
                else
                { 
                    // Construct a new initializer type in metadata for this projection (provides the 
                    // necessary context for the object materializer)
                    initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq); 
                }
                parent.ValidateInitializerMetadata(initializerMetadata);

                DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata); 

                return projection; 
            } 
        }
        private sealed class MemberInitTranslator 
            : TypedTranslator
        {
            internal MemberInitTranslator()
                : base(ExpressionType.MemberInit) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)
            { 
                if (null == linq.NewExpression.Constructor || 
                    0 != linq.NewExpression.Constructor.GetParameters().Length)
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
                }

                parent.CheckInitializerType(linq.Type); 

                List> recordColumns = 
                    new List>(linq.Bindings.Count + 1); 
                MemberInfo[] members = new MemberInfo[linq.Bindings.Count];
 
                HashSet memberNames = new HashSet(StringComparer.Ordinal);
                for (int i = 0; i < linq.Bindings.Count; i++)
                {
                    MemberAssignment binding = linq.Bindings[i] as MemberAssignment; 
                    if (null == binding)
                    { 
                        throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedBinding); 
                    }
                    string memberName; 
                    Type memberType;
                    MemberInfo memberInfo = TypeSystem.PropertyOrField(binding.Member, out memberName, out memberType);

                    CqtExpression memberValue = parent.TranslateExpression(binding.Expression); 
                    memberNames.Add(memberName);
                    members[i] = memberInfo; 
                    recordColumns.Add(new KeyValuePair(memberName, memberValue)); 
                }
 
                InitializerMetadata initializerMetadata;

                if (0 == recordColumns.Count)
                { 
                    // add a sentinel column because CQTs do not accept empty row types
                    recordColumns.Add(new KeyValuePair(KeyColumnName, parent._commandTree.CreateTrueExpression())); 
                    initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq.NewExpression); 
                }
                else 
                {
                    // Construct a new initializer type in metadata for this projection (provides the
                    // necessary context for the object materializer)
                    initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq, members); 
                }
                parent.ValidateInitializerMetadata(initializerMetadata); 
                DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata); 

                return projection; 
            }
        }
        private sealed class ConditionalTranslator : TypedTranslator
        { 
            internal ConditionalTranslator()
                : base(ExpressionType.Conditional) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, ConditionalExpression linq) 
            {
                // translate Test ? IfTrue : IfFalse --> CASE WHEN Test THEN IfTrue ELSE IfFalse 
                List whenExpressions = new List(1);
                whenExpressions.Add(parent.TranslateExpression(linq.Test));
                List thenExpressions = new List(1);
                thenExpressions.Add(parent.TranslateExpression(linq.IfTrue)); 
                CqtExpression elseExpression = parent.TranslateExpression(linq.IfFalse);
                return parent._commandTree.CreateCaseExpression(whenExpressions, thenExpressions, elseExpression); 
            } 
        }
        private sealed class NotSupportedTranslator : Translator 
        {
            internal NotSupportedTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes)
            { 
            }
            internal override CqtExpression Translate(ExpressionConverter parent, LinqExpression linq) 
            { 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedExpressionType(linq.NodeType));
            } 
        }
        #endregion

        #region Binary expression translators 
        private abstract class BinaryTranslator
            : TypedTranslator 
        { 
            protected BinaryTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            {
                return TranslateBinary(parent, parent.TranslateExpression(linq.Left), parent.TranslateExpression(linq.Right), linq);
            } 
            protected abstract CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq);
        } 
        private sealed class CoalesceTranslator : BinaryTranslator 
        {
            internal CoalesceTranslator() 
                : base(ExpressionType.Coalesce) { }
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                // left ?? right gets translated to: 
                // CASE WHEN IsNull(left) THEN right ELSE left
 
                // construct IsNull 
                CqtExpression isNull = parent.CreateIsNullExpression(left, linq.Left.Type);
 
                // construct case expression
                List whenExpressions = new List(1);
                whenExpressions.Add(isNull);
                List thenExpressions = new List(1); 
                thenExpressions.Add(right);
                CqtExpression caseExpression = parent._commandTree.CreateCaseExpression(whenExpressions, 
                    thenExpressions, left); 

                return caseExpression; 
            }
        }
        private sealed class AndAlsoTranslator : BinaryTranslator
        { 
            internal AndAlsoTranslator()
                : base(ExpressionType.AndAlso) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateAndExpression(left, right); 
            }
        }
        private sealed class OrElseTranslator : BinaryTranslator
        { 
            internal OrElseTranslator()
                : base(ExpressionType.OrElse) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateOrExpression(left, right); 
            }
        }
        private sealed class LessThanTranslator : BinaryTranslator
        { 
            internal LessThanTranslator()
                : base(ExpressionType.LessThan) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateLessThanExpression(left, right); 
            }
        }
        private sealed class LessThanOrEqualsTranslator : BinaryTranslator
        { 
            internal LessThanOrEqualsTranslator()
                : base(ExpressionType.LessThanOrEqual) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateLessThanOrEqualsExpression(left, right); 
            }
        }
        private sealed class GreaterThanTranslator : BinaryTranslator
        { 
            internal GreaterThanTranslator()
                : base(ExpressionType.GreaterThan) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateGreaterThanExpression(left, right); 
            }
        }
        private sealed class GreaterThanOrEqualsTranslator : BinaryTranslator
        { 
            internal GreaterThanOrEqualsTranslator()
                : base(ExpressionType.GreaterThanOrEqual) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateGreaterThanOrEqualsExpression(left, right); 
            }
        }
        private sealed class EqualsTranslator : TypedTranslator
        { 
            internal EqualsTranslator()
                : base(ExpressionType.Equal) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq) 
            {
                Expression linqLeft = linq.Left; 
                Expression linqRight = linq.Right;

                bool leftIsNull = LinqExpressionIsNullConstant(linqLeft);
                bool rightIsNull = LinqExpressionIsNullConstant(linqRight); 

                // if both values are null, short-circuit 
                if (leftIsNull && rightIsNull) { return parent._commandTree.CreateTrueExpression(); } 

                // if only one side is null, produce an IsNull statement 
                if (leftIsNull) { return CreateIsNullExpression(parent, linqRight); }
                if (rightIsNull) { return CreateIsNullExpression(parent, linqLeft); }

                // create a standard equals expression, calling utility method to compensate for null equality 
                CqtExpression cqtLeft = parent.TranslateExpression(linqLeft);
                CqtExpression cqtRight = parent.TranslateExpression(linqRight); 
                return parent.CreateEqualsExpression(cqtLeft, cqtRight, EqualsPattern.Store, linqLeft.Type, linqRight.Type); 
            }
            private static CqtExpression CreateIsNullExpression(ExpressionConverter parent, LinqExpression input) 
            {
                input = UnwrapConvert(input);

                // translate input 
                CqtExpression inputCqt = parent.TranslateExpression(input);
 
                // create IsNull expression 
                return parent.CreateIsNullExpression(inputCqt, input.Type);
            } 
            private static bool LinqExpressionIsNullConstant(LinqExpression expression)
            {
                // convert statements introduced by compiler should not affect nullness
                expression = UnwrapConvert(expression); 

                // check if the unwrapped expression is a null constant 
                if (ExpressionType.Constant != expression.NodeType) { return false; } 
                System.Linq.Expressions.ConstantExpression constant = (System.Linq.Expressions.ConstantExpression)expression;
                return null == constant.Value; 
            }
            private static LinqExpression UnwrapConvert(LinqExpression input)
            {
                // unwrap all converts 
                while (ExpressionType.Convert == input.NodeType)
                { 
                    input = ((UnaryExpression)input).Operand; 
                }
                return input; 
            }
        }
        private sealed class NotEqualsTranslator : TypedTranslator
        { 
            internal NotEqualsTranslator()
                : base(ExpressionType.NotEqual) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq) 
            {
                // rewrite as a not equals expression 
                LinqExpression notLinq = LinqExpression.Not(
                    LinqExpression.Equal(linq.Left, linq.Right));
                return parent.TranslateExpression(notLinq);
            } 
        }
        #endregion 
 
        #region Type binary expression translator
        private sealed class IsTranslator : TypedTranslator 
        {
            internal IsTranslator()
                : base(ExpressionType.TypeIs) { }
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, TypeBinaryExpression linq) 
            {
                CqtExpression operand = parent.TranslateExpression(linq.Expression); 
                TypeUsage fromType = operand.ResultType; 
                TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeIs, linq.TypeOperand, linq.Expression.Type);
                return parent._commandTree.CreateIsOfExpression(operand, toType); 
            }
        }
        #endregion
 
        #region Arithmetic expressions
        private sealed class AddTranslator : BinaryTranslator 
        { 
            internal AddTranslator()
                : base(ExpressionType.Add, ExpressionType.AddChecked) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                if (TypeSemantics.IsPrimitiveType(left.ResultType, PrimitiveTypeKind.String) &&
                   TypeSemantics.IsPrimitiveType(right.ResultType, PrimitiveTypeKind.String)) 
                {
                    // Add(string, string) => Concat(string, string) 
                    return parent.CreateCanonicalFunction(ExpressionConverter.Concat, linq, left, right); 
                }
                else 
                {
                    return parent._commandTree.CreatePlusExpression(left, right);
                }
            } 
        }
        private sealed class DivideTranslator : BinaryTranslator 
        { 
            internal DivideTranslator()
                : base(ExpressionType.Divide) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                return parent._commandTree.CreateDivideExpression(left, right);
            } 
        }
        private sealed class ModuloTranslator : BinaryTranslator 
        { 
            internal ModuloTranslator()
                : base(ExpressionType.Modulo) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                return parent._commandTree.CreateModuloExpression(left, right);
            } 
        }
        private sealed class MultiplyTranslator : BinaryTranslator 
        { 
            internal MultiplyTranslator()
                : base(ExpressionType.Multiply, ExpressionType.MultiplyChecked) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                return parent._commandTree.CreateMultiplyExpression(left, right);
            } 
        }
        private sealed class SubtractTranslator : BinaryTranslator 
        { 
            internal SubtractTranslator()
                : base(ExpressionType.Subtract, ExpressionType.SubtractChecked) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                return parent._commandTree.CreateMinusExpression(left, right);
            } 
        }
        private sealed class NegateTranslator : UnaryTranslator 
        { 
            internal NegateTranslator()
                : base(ExpressionType.Negate, ExpressionType.NegateChecked) { } 
            protected override CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand)
            {
                return parent._commandTree.CreateUnaryMinusExpression(operand);
            } 
        }
        private sealed class UnaryPlusTranslator : UnaryTranslator 
        { 
            internal UnaryPlusTranslator()
                : base(ExpressionType.UnaryPlus) { } 
            protected override DbExpression TranslateUnary(ExpressionConverter parent, UnaryExpression unary, DbExpression operand)
            {
                // +x = x
                return operand; 
            }
        } 
        #endregion 

        #region Bitwise expressions 
        private abstract class BitwiseBinaryTranslator : TypedTranslator
        {
            private readonly string _canonicalFunctionName;
 
            protected BitwiseBinaryTranslator(ExpressionType nodeType, string canonicalFunctionName)
                : base(nodeType) 
            { 
                _canonicalFunctionName = canonicalFunctionName;
            } 

            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            {
                CqtExpression left = parent.TranslateExpression(linq.Left); 
                CqtExpression right = parent.TranslateExpression(linq.Right);
 
                //If the arguments are binary we translate into logic expressions 
                if (TypeSemantics.IsBooleanType(left.ResultType))
                { 
                    return TranslateIntoLogicExpression(parent, linq, left, right);
                }

                //Otherwise we translate into bitwise canonical functions 
                return parent.CreateCanonicalFunction(_canonicalFunctionName, linq, left, right);
            } 
            protected abstract CqtExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, CqtExpression left, CqtExpression right); 
        }
        private sealed class AndTranslator : BitwiseBinaryTranslator 
        {
            internal AndTranslator()
                : base(ExpressionType.And, ExpressionConverter.BitwiseAnd) { }
            protected override CqtExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, CqtExpression left, CqtExpression right) 
            {
                return parent._commandTree.CreateAndExpression(left, right); 
            } 
        }
        private sealed class OrTranslator : BitwiseBinaryTranslator 
        {
            internal OrTranslator()
                : base(ExpressionType.Or, ExpressionConverter.BitwiseOr) { }
            protected override CqtExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, CqtExpression left, CqtExpression right) 
            {
                return parent._commandTree.CreateOrExpression(left, right); 
            } 
        }
        private sealed class ExclusiveOrTranslator : BitwiseBinaryTranslator 
        {
            internal ExclusiveOrTranslator()
                : base(ExpressionType.ExclusiveOr, ExpressionConverter.BitwiseXor) { }
            protected override CqtExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, CqtExpression left, CqtExpression right) 
            {
                //No direct translation, we translate into ((left && !right) || (!left && right)) 
                CqtExpression firstExpression = parent._commandTree.CreateAndExpression( 
                    left,
                    parent._commandTree.CreateNotExpression(right)); 

                CqtExpression secondExpression = parent._commandTree.CreateAndExpression(
                    parent._commandTree.CreateNotExpression(parent.TranslateExpression(linq.Left)),
                    parent.TranslateExpression(linq.Right)); 

                CqtExpression result = parent._commandTree.CreateOrExpression(firstExpression, secondExpression); 
                return result; 
            }
        } 
        private sealed class NotTranslator : TypedTranslator
        {
            internal NotTranslator()
                : base(ExpressionType.Not) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq)
            { 
                CqtExpression operand = parent.TranslateExpression(linq.Operand); 
                if (TypeSemantics.IsBooleanType(operand.ResultType))
                { 
                    return parent._commandTree.CreateNotExpression(operand);
                }
                return parent.CreateCanonicalFunction(ExpressionConverter.BitwiseNot, linq, operand);
            } 
        }
        #endregion 
 
        #region Unary expression translators
        private abstract class UnaryTranslator 
            : TypedTranslator
        {
            protected UnaryTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq)
            { 
                return TranslateUnary(parent, linq, parent.TranslateExpression(linq.Operand)); 
            }
            protected abstract CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand); 
        }
        private sealed class QuoteTranslator : UnaryTranslator
        {
            internal QuoteTranslator() 
                : base(ExpressionType.Quote) { }
            protected override CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand) 
            { 
                // simply return the operand: expressions compilations not cached for LINQ, so
                // parameters are always bound properly 
                return operand;
            }
        }
        private sealed class ConvertTranslator : UnaryTranslator 
        {
            internal ConvertTranslator() 
                : base(ExpressionType.Convert, ExpressionType.ConvertChecked) { } 
            protected override CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand)
            { 
                Type toClrType = unary.Type;
                Type fromClrType = unary.Operand.Type;
                CqtExpression source = parent.TranslateExpression(unary.Operand);
                return parent.CreateCastExpression(source, toClrType, fromClrType); 
            }
        } 
        private sealed class AsTranslator : UnaryTranslator 
        {
            internal AsTranslator() 
                : base(ExpressionType.TypeAs) { }
            protected override CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand)
            {
                TypeUsage fromType = operand.ResultType; 
                TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeAs, unary.Type, unary.Operand.Type);
                return parent._commandTree.CreateTreatExpression(operand, toType); 
            } 
        }
        #endregion 
    }
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner  [....], [....]
//--------------------------------------------------------------------- 
 
using System.Data.Common.CommandTrees;
using System.Collections.Generic; 
using CqtExpression = System.Data.Common.CommandTrees.DbExpression;
using LinqExpression = System.Linq.Expressions.Expression;
using System.Diagnostics;
using System.Data.Metadata.Edm; 
using System.Linq.Expressions;
using System.Reflection; 
using System.Data.Objects.DataClasses; 
using System.Globalization;
using System.Data.Entity; 
namespace System.Data.Objects.ELinq
{
    internal sealed partial class ExpressionConverter
    { 
        // Base class supporting the translation of LINQ node type(s) given a LINQ expression
        // of that type, and the "parent" translation context (the ExpressionConverter processor) 
        private abstract class Translator 
        {
            private readonly ExpressionType[] _nodeTypes; 
            protected Translator(params ExpressionType[] nodeTypes)
            {
                _nodeTypes = nodeTypes;
            } 
            // Gets LINQ node types this translator should be registed to process.
            internal IEnumerable NodeTypes { get { return _nodeTypes; } } 
            internal abstract CqtExpression Translate(ExpressionConverter parent, LinqExpression linq); 
            public override string ToString()
            { 
                return this.GetType().Name;
            }
        }
 
        #region Misc
        // Typed version of Translator 
        private abstract class TypedTranslator : Translator 
            where T_Linq : LinqExpression
        { 
            protected TypedTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes) { }
            internal override CqtExpression Translate(ExpressionConverter parent, LinqExpression linq)
            { 
                return TypedTranslate(parent, (T_Linq)linq);
            } 
            protected abstract CqtExpression TypedTranslate(ExpressionConverter parent, T_Linq linq); 
        }
        private sealed class ConstantTranslator 
            : TypedTranslator
        {
            internal ConstantTranslator()
                : base(ExpressionType.Constant) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.ConstantExpression linq)
            { 
                ObjectQuery queryOfT = linq.Value as ObjectQuery; 
                if (null != queryOfT)
                { 
                    return parent.TranslateInlineQueryOfT(queryOfT);
                }

                bool isNullValue = null == linq.Value; 

                // Remove facet information: null instances do not constrain type facets (e.g. a null string does not restrict 
                // "length" in compatibility checks) 
                TypeUsage type;
                bool typeSupported = false; 
                if (parent.TryGetValueLayerType(linq.Type, out type))
                {
                    // For constant values, support only primitive type (this is all that is supported by CQTs)
                    // For null types, also allow EntityType. Although other types claim to be supported, they 
                    // don't work (e.g. complex type, see SQL BU 543956)
                    if (type.EdmType.BuiltInTypeKind == BuiltInTypeKind.PrimitiveType || 
                        (isNullValue && type.EdmType.BuiltInTypeKind == BuiltInTypeKind.EntityType)) 
                    {
                        typeSupported = true; 
                    }
                }

                if (!typeSupported) 
                {
                    throw EntityUtil.NotSupported(Strings.ELinq_UnsupportedConstant(DescribeClrType(linq.Type), Strings.ELinq_PrimitiveTypesSample)); 
                } 

                // create a constant or null expression depending on value 
                if (isNullValue)
                {
                    return parent._commandTree.CreateNullExpression(type);
                } 
                else
                { 
                    return parent._commandTree.CreateConstantExpression(linq.Value, type); 
                }
            } 
        }
        private sealed class MemberAccessTranslator
            : TypedTranslator
        { 
            internal MemberAccessTranslator()
                : base(ExpressionType.MemberAccess) { } 
            // attempt to translate the member access to a "regular" property, a navigation property, or a calculated 
            // property
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, MemberExpression linq) 
            {
                CqtExpression propertyExpression;
                string memberName;
                Type memberType; 
                MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Member, out memberName, out memberType);
 
                // note: we check for "regular" properties last, since the other two flavors derive 
                // from this one
                if (linq.Expression != null) 
                {
                    CqtExpression instance = parent.TranslateExpression(linq.Expression);
                    if (TryResolveAsProperty(parent, memberInfo,
                        instance.ResultType, instance, out propertyExpression)) 
                    {
                        return propertyExpression; 
                    } 
                }
 
                if (memberInfo.MemberType == MemberTypes.Property)
                {
                    // Check whether it is one of the special proeperties that we know how to translate
                    PropertyTranslator propertyTranslator; 
                    if (TryGetTranslator((PropertyInfo)memberInfo, out propertyTranslator))
                    { 
                        return propertyTranslator.Translate(parent, linq); 
                    }
                } 

                // no other property types are supported by LINQ over entities
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnrecognizedMember(linq.Member.Name));
            } 

            #region Static members and initializers 
            private static readonly Dictionary s_propertyTranslators; 
            private static bool s_vbPropertiesInitialized;
            private static readonly object s_vbInitializerLock = new object(); 

            static MemberAccessTranslator()
            {
                // initialize translators for specific properties 
                s_propertyTranslators = new Dictionary();
                foreach (PropertyTranslator translator in GetPropertyTranslators()) 
                { 
                    foreach (PropertyInfo property in translator.Properties)
                    { 
                        s_propertyTranslators.Add(property, translator);
                    }
                }
            } 

            ///  
            /// Tries to get a translator for the given property info. 
            /// If the given property info corresponds to a Visual Basic property,
            /// it also initializes the Visual Basic translators if they have not been initialized 
            /// 
            /// 
            /// 
            ///  
            private static bool TryGetTranslator(PropertyInfo propertyInfo, out PropertyTranslator propertyTranslator)
            { 
                //If the type is generic, we try to match the generic property 
                if (propertyInfo.DeclaringType.IsGenericType)
                { 
                    try
                    {
                        propertyInfo = propertyInfo.DeclaringType.GetGenericTypeDefinition().GetProperty(propertyInfo.Name, BindingFlags.DeclaredOnly | BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public);
                    } 
                    catch (AmbiguousMatchException)
                    { 
                        propertyTranslator = null; 
                        return false;
                    } 
                    if (propertyInfo == null)
                    {
                        propertyTranslator = null;
                        return false; 
                    }
                } 
 
                if (s_propertyTranslators.TryGetValue(propertyInfo, out propertyTranslator))
                { 
                    return true;
                }

                // check if this is the visual basic assembly 
                if (s_visualBasicAssemblyFullName == propertyInfo.DeclaringType.Assembly.FullName)
                { 
                    lock (s_vbInitializerLock) 
                    {
                        if (!s_vbPropertiesInitialized) 
                        {
                            InitializeVBProperties(propertyInfo.DeclaringType.Assembly);
                            s_vbPropertiesInitialized = true;
                        } 
                        // try again
                        return s_propertyTranslators.TryGetValue(propertyInfo, out propertyTranslator); 
                    } 
                }
                propertyTranslator = null; 
                return false;
            }

            // Determines if the given property can be resolved as a standard or navigation property. 
            private static bool TryResolveAsProperty(ExpressionConverter parent,
                MemberInfo clrMember, TypeUsage definingType, CqtExpression instance, out CqtExpression propertyExpression) 
            { 
                // retrieve members directly from row types, which are not mapped between O and C
                RowType rowType = definingType.EdmType as RowType; 
                string name = clrMember.Name;

                if (null != rowType)
                { 
                    EdmMember member;
                    if (rowType.Members.TryGetValue(name, false, out member)) 
                    { 
                        propertyExpression = parent._commandTree.CreatePropertyExpression(name, instance);
                        return true; 
                    }

                    propertyExpression = null;
                    return false; 
                }
 
                // for non-row structural types, map from the O to the C layer using the perspective 
                StructuralType structuralType = definingType.EdmType as StructuralType;
                if (null != structuralType) 
                {
                    EdmMember member = null;
                    if (parent._typeResolver.Perspective.TryGetMember(structuralType, name, false, out member))
                    { 
                        if (null != member)
                        { 
                            if (member.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty) 
                            {
                                NavigationProperty navProp = (NavigationProperty)member; 
                                propertyExpression = TranslateNavigationProperty(parent, clrMember, instance, navProp);
                                return true;
                            }
                            else 
                            {
                                // if we're accessing a key member of a navigation, collapse the structure instance 
                                // to the key reference. 
                                instance = NormalizeInstanceForReference(parent, instance, member);
                                propertyExpression = parent._commandTree.CreatePropertyExpression(name, instance); 
                                return true;
                            }

                        } 
                    }
                } 
 
                // try to unwrap GroupBy "Key" member
                if (name == ExpressionConverter.KeyColumnName) 
                {
                    // see if we can "unwrap" the current instance
                    if (DbExpressionKind.Property == instance.ExpressionKind)
                    { 
                        DbPropertyExpression property = (DbPropertyExpression)instance;
                        InitializerMetadata initializerMetadata; 
 
                        // if we're dealing with the "Group" property of a GroupBy projection, we know how to unwrap
                        // it 
                        if (property.Property.Name == ExpressionConverter.GroupColumnName && // only know how to unwrap the group
                            InitializerMetadata.TryGetInitializerMetadata(property.Instance.ResultType, out initializerMetadata) &&
                            initializerMetadata.Kind == InitializerMetadataKind.Grouping)
                        { 
                            propertyExpression = parent._commandTree.CreatePropertyExpression(ExpressionConverter.KeyColumnName,
                                property.Instance); 
                            return true; 
                        }
                    } 
                }

                propertyExpression = null;
                return false; 
            }
 
            ///  
            /// We simplify the property instance where the user is accessing a key member of
            /// a reference navigation. The instance becomes simply the reference key in such 
            /// cases.
            ///
            /// For instance, product.Category.CategoryID becomes Ref(product.Category).CategoryID,
            /// which gives us a chance of optimizing the query (using foreign keys rather than joins) 
            /// 
            /// Conversion context. 
            /// Instance from which we're accessing member. 
            /// Member we're accessing.
            /// 'Simplified' instance. If the member is a key and the instance is a navigation 
            /// the returned instance is a reference navigation rather than the full entity.
            private static CqtExpression NormalizeInstanceForReference(ExpressionConverter parent, CqtExpression instance, EdmMember member)
            {
                EdmType instanceType = instance.ResultType.EdmType; 

                if (instanceType.BuiltInTypeKind == BuiltInTypeKind.EntityType) 
                { 
                    EntityType entityType = (EntityType)instanceType;
                    if (entityType.KeyMembers.Contains(member) && instance.ExpressionKind == DbExpressionKind.Property) 
                    {
                        DbPropertyExpression propertyExpression = (DbPropertyExpression)instance;
                        if (propertyExpression.Property.BuiltInTypeKind == BuiltInTypeKind.NavigationProperty)
                        { 
                            // modify the property expression so that it merely retrieves the reference
                            // not the entire entity 
                            NavigationProperty navigationProperty = (NavigationProperty)propertyExpression.Property; 

                            DbExpression navigationSource = parent._commandTree.CreateEntityRefExpression(propertyExpression.Instance); 
                            DbExpression navigationExpression = parent._commandTree.CreateRelationshipNavigationExpression(
                                navigationProperty.FromEndMember,
                                navigationProperty.ToEndMember,
                                navigationSource); 
                            instance = parent._commandTree.CreateRefKeyExpression(navigationExpression);
                        } 
                    } 
                }
                return instance; 
            }

            private static CqtExpression TranslateNavigationProperty(ExpressionConverter parent, MemberInfo clrMember, CqtExpression instance, NavigationProperty navProp)
            { 
                CqtExpression propertyExpression;
                propertyExpression = parent._commandTree.CreatePropertyExpression(navProp, instance); 
 
                // for EntityCollection navigations, wrap in "grouping" where the key is the parent
                // entity and the group contains the child entities 
                if (BuiltInTypeKind.CollectionType == propertyExpression.ResultType.EdmType.BuiltInTypeKind)
                {
                    List> collectionColumns =
                        new List>(2); 
                    collectionColumns.Add(new KeyValuePair(
                        ExpressionConverter.EntityCollectionOwnerColumnName, instance)); 
                    collectionColumns.Add(new KeyValuePair( 
                        ExpressionConverter.EntityCollectionElementsColumnName, propertyExpression));
                    propertyExpression = parent.CreateNewRowExpression(collectionColumns, 
                        InitializerMetadata.CreateEntityCollectionInitializer(parent.EdmItemCollection, ((PropertyInfo)clrMember).PropertyType, navProp));
                }
                return propertyExpression;
            } 

            private static void InitializeVBProperties(Assembly vbAssembly) 
            { 
                Debug.Assert(!s_vbPropertiesInitialized);
                foreach (PropertyTranslator translator in GetVisualBasicPropertyTranslators(vbAssembly)) 
                {
                    foreach (PropertyInfo property in translator.Properties)
                    {
                        s_propertyTranslators.Add(property, translator); 
                    }
                } 
            } 

            private static IEnumerable GetVisualBasicPropertyTranslators(Assembly vbAssembly) 
            {
                yield return new VBDateAndTimeNowTranslator(vbAssembly);
            }
 
            private static IEnumerable GetPropertyTranslators()
            { 
                yield return new DefaultCanonicalFunctionPropertyTranslator(); 
                yield return new RenameCanonicalFunctionPropertyTranslator();
                yield return new EntityCollectionCountTranslator(); 
                yield return new NullableHasValueTranslator();
                yield return new NullableValueTranslator();
            }
 
            /// 
            /// Checks whether the given property info can be translated into a canonical function. 
            /// This method is used to determine whether client side evaluation should be done, 
            /// if the property can be evaluated in the store, it is not being evaluated on the client
            ///  
            /// 
            /// 
            internal static bool CanTranslatePropertyInfo(PropertyInfo propertyInfo)
            { 
                PropertyTranslator propertyTranslator;
                return TryGetTranslator(propertyInfo, out propertyTranslator); 
            } 
            #endregion
 
            #region Property Translators
            private abstract class PropertyTranslator
            {
                private readonly IEnumerable _properties; 
                protected PropertyTranslator(params PropertyInfo[] properties) { _properties = properties; }
                protected PropertyTranslator(IEnumerable properties) { _properties = properties; } 
                internal IEnumerable Properties { get { return _properties; } } 
                internal abstract CqtExpression Translate(ExpressionConverter parent, MemberExpression call);
                public override string ToString() 
                {
                    return GetType().Name;
                }
            } 

            private sealed class DefaultCanonicalFunctionPropertyTranslator : PropertyTranslator 
            { 
                internal DefaultCanonicalFunctionPropertyTranslator()
                    : base(GetProperties()) { } 

                private static IEnumerable GetProperties()
                {
                    yield return typeof(String).GetProperty("Length", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTime).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTime).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance);

                    yield return typeof(DateTimeOffset).GetProperty("Year", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Month", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Day", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Hour", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Minute", BindingFlags.Public | BindingFlags.Instance);
                    yield return typeof(DateTimeOffset).GetProperty("Second", BindingFlags.Public | BindingFlags.Instance); 
                    yield return typeof(DateTimeOffset).GetProperty("Millisecond", BindingFlags.Public | BindingFlags.Instance);
                }

                // Default translator for method calls into canonical functions. 
                // Translation:
                //      object.PropertyName  -> PropertyName(object) 
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call) 
                {
                    return parent.TranslateIntoCanonicalFunction(call.Member.Name, call, call.Expression); 
                }
            }

            private sealed class RenameCanonicalFunctionPropertyTranslator : PropertyTranslator 
            {
                private static readonly Dictionary s_propertyRenameMap = new Dictionary(2); 
 
                internal RenameCanonicalFunctionPropertyTranslator()
                    : base(GetProperties()) { } 

                private static IEnumerable GetProperties()
                {
                    yield return GetProperty(typeof(DateTime), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTime); 
                    yield return GetProperty(typeof(DateTime), "UtcNow", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentUtcDateTime);
                    yield return GetProperty(typeof(DateTimeOffset), "Now", BindingFlags.Public | BindingFlags.Static, ExpressionConverter.CurrentDateTimeOffset); 
 
                    yield return GetProperty(typeof(TimeSpan), "Hours", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Hour);
                    yield return GetProperty(typeof(TimeSpan), "Minutes", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Minute); 
                    yield return GetProperty(typeof(TimeSpan), "Seconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Second);
                    yield return GetProperty(typeof(TimeSpan), "Milliseconds", BindingFlags.Public | BindingFlags.Instance, ExpressionConverter.Millisecond);
                }
 
                private static PropertyInfo GetProperty(Type declaringType, string propertyName, BindingFlags bindingFlages, string canonicalFunctionName)
                { 
                    PropertyInfo propertyInfo = declaringType.GetProperty(propertyName, bindingFlages); 
                    s_propertyRenameMap.Add(propertyInfo, canonicalFunctionName);
                    return propertyInfo; 
                }

                // Translator for static properties into canonical functions when there is a corresponding
                // canonical function but with a differnet name 
                // Translation:
                //      object.PropertyName  -> CanonicalFunctionName(object) 
                //      Type.PropertyName  -> CanonicalFunctionName() 
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    PropertyInfo property = (PropertyInfo)call.Member;
                    String canonicalFunctionName = s_propertyRenameMap[property];
                    CqtExpression result;
                    if (call.Expression == null) 
                    {
                        result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call); 
                    } 
                    else
                    { 
                        result = parent.TranslateIntoCanonicalFunction(canonicalFunctionName, call, call.Expression);
                    }
                    return result;
                } 
            }
 
            private sealed class VBDateAndTimeNowTranslator : PropertyTranslator 
            {
                private const string s_dateAndTimeTypeFullName = "Microsoft.VisualBasic.DateAndTime"; 

                internal VBDateAndTimeNowTranslator(Assembly vbAssembly)
                    : base(GetProperty(vbAssembly)) { }
 
                private static PropertyInfo GetProperty(Assembly vbAssembly)
                { 
                    return vbAssembly.GetType(s_dateAndTimeTypeFullName).GetProperty("Now", BindingFlags.Public | BindingFlags.Static); 
                }
 
                // Translation:
                //      Now -> GetDate()
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    return parent.TranslateIntoCanonicalFunction(ExpressionConverter.CurrentDateTime, call);
                } 
            } 

            private sealed class EntityCollectionCountTranslator : PropertyTranslator 
            {
                internal EntityCollectionCountTranslator()
                    : base(GetProperty()) { }
 
                private static PropertyInfo GetProperty()
                { 
                    return typeof(EntityCollection<>).GetProperty(ExpressionConverter.s_entityCollectionCountPropertyName, BindingFlags.Public | BindingFlags.Instance); 
                }
 
                // Translation:
                //      EntityCollection.Count -> Count()
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    // retranslate as a Count() aggregate, since the name collision prevents us
                    // from calling the method directly in VB and C# 
                    MethodInfo countMethod; 
                    ReflectionUtil.TryLookupMethod(SequenceMethod.Count, out countMethod);
                    Debug.Assert(null != countMethod, "Count() must exist"); 
                    countMethod = countMethod.MakeGenericMethod(call.Member.DeclaringType.GetGenericArguments());
                    LinqExpression countCall = LinqExpression.Call(countMethod, call.Expression);
                    return parent.TranslateExpression(countCall);
                } 
            }
 
            private sealed class NullableHasValueTranslator : PropertyTranslator 
            {
                internal NullableHasValueTranslator() 
                    : base(GetProperty()) { }

                private static PropertyInfo GetProperty()
                { 
                    return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableHasValuePropertyName, BindingFlags.Public | BindingFlags.Instance);
                } 
 
                // Translation:
                //      Nullable.HasValue -> Not(IsNull(arg)) 
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                {
                    CqtExpression argument = parent.TranslateExpression(call.Expression);
                    Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type"); 
                    return parent._commandTree.CreateNotExpression(parent.CreateIsNullExpression(argument, call.Expression.Type));
                } 
            } 

            private sealed class NullableValueTranslator : PropertyTranslator 
            {
                internal NullableValueTranslator()
                    : base(GetProperty()) { }
 
                private static PropertyInfo GetProperty()
                { 
                    return typeof(Nullable<>).GetProperty(ExpressionConverter.s_nullableValuePropertyName, BindingFlags.Public | BindingFlags.Instance); 
                }
 
                // Translation:
                //      Nullable.Value -> arg
                internal override CqtExpression Translate(ExpressionConverter parent, MemberExpression call)
                { 
                    CqtExpression argument = parent.TranslateExpression(call.Expression);
                    Debug.Assert(!TypeSemantics.IsCollectionType(argument.ResultType), "Did not expect collection type"); 
                    return argument; 
                }
            } 
            #endregion
        }
        private sealed class ParameterTranslator
            : TypedTranslator 
        {
            internal ParameterTranslator() 
                : base(ExpressionType.Parameter) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, ParameterExpression linq)
            { 
                // Bindings should be intercepted before we get to this point (in ExpressionConverter.TranslateExpression)
                if (parent._bindingContext.IsRootContextParameter(linq))
                {
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnsupportedUseOfContextParameter(linq.Name)); 
                }
                else 
                { 
                    throw EntityUtil.InvalidOperation(System.Data.Entity.Strings.ELinq_UnboundParameterExpression(linq.Name));
                } 
            }
        }
        private sealed class NewTranslator
            : TypedTranslator 
        {
            internal NewTranslator() 
                : base(ExpressionType.New) { } 
            protected override DbExpression TypedTranslate(ExpressionConverter parent, NewExpression linq)
            { 
                int memberCount = null == linq.Members ? 0 : linq.Members.Count;

                if (null == linq.Constructor ||
                    linq.Arguments.Count != memberCount) 
                {
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor); 
                } 

                parent.CheckInitializerType(linq.Type); 

                List> recordColumns =
                    new List>(memberCount + 1);
 
                HashSet memberNames = new HashSet(StringComparer.Ordinal);
                for (int i = 0; i < memberCount; i++) 
                { 
                    string memberName;
                    Type memberType; 
                    MemberInfo memberInfo = TypeSystem.PropertyOrField(linq.Members[i], out memberName, out memberType);
                    CqtExpression memberValue = parent.TranslateExpression(linq.Arguments[i]);
                    memberNames.Add(memberName);
                    recordColumns.Add(new KeyValuePair(memberName, memberValue)); 
                }
 
                InitializerMetadata initializerMetadata; 
                if (0 == memberCount)
                { 
                    // add a sentinel column because CQTs do not accept empty row types
                    recordColumns.Add(new KeyValuePair(KeyColumnName, parent._commandTree.CreateTrueExpression()));
                    initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq);
                } 
                else
                { 
                    // Construct a new initializer type in metadata for this projection (provides the 
                    // necessary context for the object materializer)
                    initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq); 
                }
                parent.ValidateInitializerMetadata(initializerMetadata);

                DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata); 

                return projection; 
            } 
        }
        private sealed class MemberInitTranslator 
            : TypedTranslator
        {
            internal MemberInitTranslator()
                : base(ExpressionType.MemberInit) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, MemberInitExpression linq)
            { 
                if (null == linq.NewExpression.Constructor || 
                    0 != linq.NewExpression.Constructor.GetParameters().Length)
                { 
                    throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedConstructor);
                }

                parent.CheckInitializerType(linq.Type); 

                List> recordColumns = 
                    new List>(linq.Bindings.Count + 1); 
                MemberInfo[] members = new MemberInfo[linq.Bindings.Count];
 
                HashSet memberNames = new HashSet(StringComparer.Ordinal);
                for (int i = 0; i < linq.Bindings.Count; i++)
                {
                    MemberAssignment binding = linq.Bindings[i] as MemberAssignment; 
                    if (null == binding)
                    { 
                        throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedBinding); 
                    }
                    string memberName; 
                    Type memberType;
                    MemberInfo memberInfo = TypeSystem.PropertyOrField(binding.Member, out memberName, out memberType);

                    CqtExpression memberValue = parent.TranslateExpression(binding.Expression); 
                    memberNames.Add(memberName);
                    members[i] = memberInfo; 
                    recordColumns.Add(new KeyValuePair(memberName, memberValue)); 
                }
 
                InitializerMetadata initializerMetadata;

                if (0 == recordColumns.Count)
                { 
                    // add a sentinel column because CQTs do not accept empty row types
                    recordColumns.Add(new KeyValuePair(KeyColumnName, parent._commandTree.CreateTrueExpression())); 
                    initializerMetadata = InitializerMetadata.CreateEmptyProjectionInitializer(parent.EdmItemCollection, linq.NewExpression); 
                }
                else 
                {
                    // Construct a new initializer type in metadata for this projection (provides the
                    // necessary context for the object materializer)
                    initializerMetadata = InitializerMetadata.CreateProjectionInitializer(parent.EdmItemCollection, linq, members); 
                }
                parent.ValidateInitializerMetadata(initializerMetadata); 
                DbNewInstanceExpression projection = parent.CreateNewRowExpression(recordColumns, initializerMetadata); 

                return projection; 
            }
        }
        private sealed class ConditionalTranslator : TypedTranslator
        { 
            internal ConditionalTranslator()
                : base(ExpressionType.Conditional) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, ConditionalExpression linq) 
            {
                // translate Test ? IfTrue : IfFalse --> CASE WHEN Test THEN IfTrue ELSE IfFalse 
                List whenExpressions = new List(1);
                whenExpressions.Add(parent.TranslateExpression(linq.Test));
                List thenExpressions = new List(1);
                thenExpressions.Add(parent.TranslateExpression(linq.IfTrue)); 
                CqtExpression elseExpression = parent.TranslateExpression(linq.IfFalse);
                return parent._commandTree.CreateCaseExpression(whenExpressions, thenExpressions, elseExpression); 
            } 
        }
        private sealed class NotSupportedTranslator : Translator 
        {
            internal NotSupportedTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes)
            { 
            }
            internal override CqtExpression Translate(ExpressionConverter parent, LinqExpression linq) 
            { 
                throw EntityUtil.NotSupported(System.Data.Entity.Strings.ELinq_UnsupportedExpressionType(linq.NodeType));
            } 
        }
        #endregion

        #region Binary expression translators 
        private abstract class BinaryTranslator
            : TypedTranslator 
        { 
            protected BinaryTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            {
                return TranslateBinary(parent, parent.TranslateExpression(linq.Left), parent.TranslateExpression(linq.Right), linq);
            } 
            protected abstract CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq);
        } 
        private sealed class CoalesceTranslator : BinaryTranslator 
        {
            internal CoalesceTranslator() 
                : base(ExpressionType.Coalesce) { }
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                // left ?? right gets translated to: 
                // CASE WHEN IsNull(left) THEN right ELSE left
 
                // construct IsNull 
                CqtExpression isNull = parent.CreateIsNullExpression(left, linq.Left.Type);
 
                // construct case expression
                List whenExpressions = new List(1);
                whenExpressions.Add(isNull);
                List thenExpressions = new List(1); 
                thenExpressions.Add(right);
                CqtExpression caseExpression = parent._commandTree.CreateCaseExpression(whenExpressions, 
                    thenExpressions, left); 

                return caseExpression; 
            }
        }
        private sealed class AndAlsoTranslator : BinaryTranslator
        { 
            internal AndAlsoTranslator()
                : base(ExpressionType.AndAlso) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateAndExpression(left, right); 
            }
        }
        private sealed class OrElseTranslator : BinaryTranslator
        { 
            internal OrElseTranslator()
                : base(ExpressionType.OrElse) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateOrExpression(left, right); 
            }
        }
        private sealed class LessThanTranslator : BinaryTranslator
        { 
            internal LessThanTranslator()
                : base(ExpressionType.LessThan) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateLessThanExpression(left, right); 
            }
        }
        private sealed class LessThanOrEqualsTranslator : BinaryTranslator
        { 
            internal LessThanOrEqualsTranslator()
                : base(ExpressionType.LessThanOrEqual) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateLessThanOrEqualsExpression(left, right); 
            }
        }
        private sealed class GreaterThanTranslator : BinaryTranslator
        { 
            internal GreaterThanTranslator()
                : base(ExpressionType.GreaterThan) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateGreaterThanExpression(left, right); 
            }
        }
        private sealed class GreaterThanOrEqualsTranslator : BinaryTranslator
        { 
            internal GreaterThanOrEqualsTranslator()
                : base(ExpressionType.GreaterThanOrEqual) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq) 
            {
                return parent._commandTree.CreateGreaterThanOrEqualsExpression(left, right); 
            }
        }
        private sealed class EqualsTranslator : TypedTranslator
        { 
            internal EqualsTranslator()
                : base(ExpressionType.Equal) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq) 
            {
                Expression linqLeft = linq.Left; 
                Expression linqRight = linq.Right;

                bool leftIsNull = LinqExpressionIsNullConstant(linqLeft);
                bool rightIsNull = LinqExpressionIsNullConstant(linqRight); 

                // if both values are null, short-circuit 
                if (leftIsNull && rightIsNull) { return parent._commandTree.CreateTrueExpression(); } 

                // if only one side is null, produce an IsNull statement 
                if (leftIsNull) { return CreateIsNullExpression(parent, linqRight); }
                if (rightIsNull) { return CreateIsNullExpression(parent, linqLeft); }

                // create a standard equals expression, calling utility method to compensate for null equality 
                CqtExpression cqtLeft = parent.TranslateExpression(linqLeft);
                CqtExpression cqtRight = parent.TranslateExpression(linqRight); 
                return parent.CreateEqualsExpression(cqtLeft, cqtRight, EqualsPattern.Store, linqLeft.Type, linqRight.Type); 
            }
            private static CqtExpression CreateIsNullExpression(ExpressionConverter parent, LinqExpression input) 
            {
                input = UnwrapConvert(input);

                // translate input 
                CqtExpression inputCqt = parent.TranslateExpression(input);
 
                // create IsNull expression 
                return parent.CreateIsNullExpression(inputCqt, input.Type);
            } 
            private static bool LinqExpressionIsNullConstant(LinqExpression expression)
            {
                // convert statements introduced by compiler should not affect nullness
                expression = UnwrapConvert(expression); 

                // check if the unwrapped expression is a null constant 
                if (ExpressionType.Constant != expression.NodeType) { return false; } 
                System.Linq.Expressions.ConstantExpression constant = (System.Linq.Expressions.ConstantExpression)expression;
                return null == constant.Value; 
            }
            private static LinqExpression UnwrapConvert(LinqExpression input)
            {
                // unwrap all converts 
                while (ExpressionType.Convert == input.NodeType)
                { 
                    input = ((UnaryExpression)input).Operand; 
                }
                return input; 
            }
        }
        private sealed class NotEqualsTranslator : TypedTranslator
        { 
            internal NotEqualsTranslator()
                : base(ExpressionType.NotEqual) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq) 
            {
                // rewrite as a not equals expression 
                LinqExpression notLinq = LinqExpression.Not(
                    LinqExpression.Equal(linq.Left, linq.Right));
                return parent.TranslateExpression(notLinq);
            } 
        }
        #endregion 
 
        #region Type binary expression translator
        private sealed class IsTranslator : TypedTranslator 
        {
            internal IsTranslator()
                : base(ExpressionType.TypeIs) { }
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, TypeBinaryExpression linq) 
            {
                CqtExpression operand = parent.TranslateExpression(linq.Expression); 
                TypeUsage fromType = operand.ResultType; 
                TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeIs, linq.TypeOperand, linq.Expression.Type);
                return parent._commandTree.CreateIsOfExpression(operand, toType); 
            }
        }
        #endregion
 
        #region Arithmetic expressions
        private sealed class AddTranslator : BinaryTranslator 
        { 
            internal AddTranslator()
                : base(ExpressionType.Add, ExpressionType.AddChecked) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                if (TypeSemantics.IsPrimitiveType(left.ResultType, PrimitiveTypeKind.String) &&
                   TypeSemantics.IsPrimitiveType(right.ResultType, PrimitiveTypeKind.String)) 
                {
                    // Add(string, string) => Concat(string, string) 
                    return parent.CreateCanonicalFunction(ExpressionConverter.Concat, linq, left, right); 
                }
                else 
                {
                    return parent._commandTree.CreatePlusExpression(left, right);
                }
            } 
        }
        private sealed class DivideTranslator : BinaryTranslator 
        { 
            internal DivideTranslator()
                : base(ExpressionType.Divide) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                return parent._commandTree.CreateDivideExpression(left, right);
            } 
        }
        private sealed class ModuloTranslator : BinaryTranslator 
        { 
            internal ModuloTranslator()
                : base(ExpressionType.Modulo) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                return parent._commandTree.CreateModuloExpression(left, right);
            } 
        }
        private sealed class MultiplyTranslator : BinaryTranslator 
        { 
            internal MultiplyTranslator()
                : base(ExpressionType.Multiply, ExpressionType.MultiplyChecked) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                return parent._commandTree.CreateMultiplyExpression(left, right);
            } 
        }
        private sealed class SubtractTranslator : BinaryTranslator 
        { 
            internal SubtractTranslator()
                : base(ExpressionType.Subtract, ExpressionType.SubtractChecked) { } 
            protected override CqtExpression TranslateBinary(ExpressionConverter parent, CqtExpression left, CqtExpression right, BinaryExpression linq)
            {
                return parent._commandTree.CreateMinusExpression(left, right);
            } 
        }
        private sealed class NegateTranslator : UnaryTranslator 
        { 
            internal NegateTranslator()
                : base(ExpressionType.Negate, ExpressionType.NegateChecked) { } 
            protected override CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand)
            {
                return parent._commandTree.CreateUnaryMinusExpression(operand);
            } 
        }
        private sealed class UnaryPlusTranslator : UnaryTranslator 
        { 
            internal UnaryPlusTranslator()
                : base(ExpressionType.UnaryPlus) { } 
            protected override DbExpression TranslateUnary(ExpressionConverter parent, UnaryExpression unary, DbExpression operand)
            {
                // +x = x
                return operand; 
            }
        } 
        #endregion 

        #region Bitwise expressions 
        private abstract class BitwiseBinaryTranslator : TypedTranslator
        {
            private readonly string _canonicalFunctionName;
 
            protected BitwiseBinaryTranslator(ExpressionType nodeType, string canonicalFunctionName)
                : base(nodeType) 
            { 
                _canonicalFunctionName = canonicalFunctionName;
            } 

            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq)
            {
                CqtExpression left = parent.TranslateExpression(linq.Left); 
                CqtExpression right = parent.TranslateExpression(linq.Right);
 
                //If the arguments are binary we translate into logic expressions 
                if (TypeSemantics.IsBooleanType(left.ResultType))
                { 
                    return TranslateIntoLogicExpression(parent, linq, left, right);
                }

                //Otherwise we translate into bitwise canonical functions 
                return parent.CreateCanonicalFunction(_canonicalFunctionName, linq, left, right);
            } 
            protected abstract CqtExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, CqtExpression left, CqtExpression right); 
        }
        private sealed class AndTranslator : BitwiseBinaryTranslator 
        {
            internal AndTranslator()
                : base(ExpressionType.And, ExpressionConverter.BitwiseAnd) { }
            protected override CqtExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, CqtExpression left, CqtExpression right) 
            {
                return parent._commandTree.CreateAndExpression(left, right); 
            } 
        }
        private sealed class OrTranslator : BitwiseBinaryTranslator 
        {
            internal OrTranslator()
                : base(ExpressionType.Or, ExpressionConverter.BitwiseOr) { }
            protected override CqtExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, CqtExpression left, CqtExpression right) 
            {
                return parent._commandTree.CreateOrExpression(left, right); 
            } 
        }
        private sealed class ExclusiveOrTranslator : BitwiseBinaryTranslator 
        {
            internal ExclusiveOrTranslator()
                : base(ExpressionType.ExclusiveOr, ExpressionConverter.BitwiseXor) { }
            protected override CqtExpression TranslateIntoLogicExpression(ExpressionConverter parent, System.Linq.Expressions.BinaryExpression linq, CqtExpression left, CqtExpression right) 
            {
                //No direct translation, we translate into ((left && !right) || (!left && right)) 
                CqtExpression firstExpression = parent._commandTree.CreateAndExpression( 
                    left,
                    parent._commandTree.CreateNotExpression(right)); 

                CqtExpression secondExpression = parent._commandTree.CreateAndExpression(
                    parent._commandTree.CreateNotExpression(parent.TranslateExpression(linq.Left)),
                    parent.TranslateExpression(linq.Right)); 

                CqtExpression result = parent._commandTree.CreateOrExpression(firstExpression, secondExpression); 
                return result; 
            }
        } 
        private sealed class NotTranslator : TypedTranslator
        {
            internal NotTranslator()
                : base(ExpressionType.Not) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq)
            { 
                CqtExpression operand = parent.TranslateExpression(linq.Operand); 
                if (TypeSemantics.IsBooleanType(operand.ResultType))
                { 
                    return parent._commandTree.CreateNotExpression(operand);
                }
                return parent.CreateCanonicalFunction(ExpressionConverter.BitwiseNot, linq, operand);
            } 
        }
        #endregion 
 
        #region Unary expression translators
        private abstract class UnaryTranslator 
            : TypedTranslator
        {
            protected UnaryTranslator(params ExpressionType[] nodeTypes)
                : base(nodeTypes) { } 
            protected override CqtExpression TypedTranslate(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression linq)
            { 
                return TranslateUnary(parent, linq, parent.TranslateExpression(linq.Operand)); 
            }
            protected abstract CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand); 
        }
        private sealed class QuoteTranslator : UnaryTranslator
        {
            internal QuoteTranslator() 
                : base(ExpressionType.Quote) { }
            protected override CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand) 
            { 
                // simply return the operand: expressions compilations not cached for LINQ, so
                // parameters are always bound properly 
                return operand;
            }
        }
        private sealed class ConvertTranslator : UnaryTranslator 
        {
            internal ConvertTranslator() 
                : base(ExpressionType.Convert, ExpressionType.ConvertChecked) { } 
            protected override CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand)
            { 
                Type toClrType = unary.Type;
                Type fromClrType = unary.Operand.Type;
                CqtExpression source = parent.TranslateExpression(unary.Operand);
                return parent.CreateCastExpression(source, toClrType, fromClrType); 
            }
        } 
        private sealed class AsTranslator : UnaryTranslator 
        {
            internal AsTranslator() 
                : base(ExpressionType.TypeAs) { }
            protected override CqtExpression TranslateUnary(ExpressionConverter parent, System.Linq.Expressions.UnaryExpression unary, CqtExpression operand)
            {
                TypeUsage fromType = operand.ResultType; 
                TypeUsage toType = parent.GetIsOrAsTargetType(fromType, ExpressionType.TypeAs, unary.Type, unary.Operand.Type);
                return parent._commandTree.CreateTreatExpression(operand, toType); 
            } 
        }
        #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