translator.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Common / internal / materialization / translator.cs / 1599186 / translator.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
using System.Collections.Generic;
using System.Data; 
using System.Data.Common.QueryCache;
using System.Data.Common.Utils;
using System.Data.Entity;
using System.Data.Mapping; 
using System.Data.Metadata.Edm;
using System.Data.Objects; 
using System.Data.Objects.ELinq; 
using System.Data.Objects.Internal;
using System.Data.Query.InternalTrees; 
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Linq.Expressions; 
using System.Reflection;
using System.Security.Permissions; 
using System.Security; 
using System.Text;
using System.Data.Objects.DataClasses; 
using System.Runtime.CompilerServices;

namespace System.Data.Common.Internal.Materialization
{ 
    /// 
    /// Struct containing the requested type and parent column map used 
    /// as the arg in the Translator visitor. 
    /// 
    internal struct TranslatorArg 
    {
        internal readonly Type RequestedType;

        internal TranslatorArg(Type requestedType) 
        {
            this.RequestedType = requestedType; 
        } 
    }
 
    /// 
    /// Type returned by the Translator visitor; allows us to put the logic
    /// to ensure a specific return type in a single place, instead of in
    /// each Visit method. 
    /// 
    internal class TranslatorResult 
    { 
        private readonly Expression ReturnedExpression;
        private readonly Type RequestedType; 

        internal TranslatorResult(Expression returnedExpression, Type requestedType)
        {
            this.RequestedType = requestedType; 
            this.ReturnedExpression = returnedExpression;
        } 
 
        /// 
        /// Return the expression; wrapped with the appropriate cast/convert 
        /// logic to guarantee it's type.
        /// 
        internal Expression Expression
        { 
            get
            { 
                Expression result = Translator.Emit_EnsureType(ReturnedExpression, RequestedType); 
                return result;
            } 
        }

        /// 
        /// Return the expression without attempting to cast/convert to the requested type. 
        /// 
        internal Expression UnconvertedExpression 
        { 
            get
            { 
                return ReturnedExpression;
            }
        }
 
        /// 
        /// Checks if the expression represents an wrapped entity and if so creates an expression 
        /// that extracts the raw entity from the wrapper. 
        /// 
        internal Expression UnwrappedExpression 
        {
            get
            {
                if (!typeof(IEntityWrapper).IsAssignableFrom(ReturnedExpression.Type)) 
                {
                    return ReturnedExpression; 
                } 
                return Translator.Emit_UnwrapAndEnsureType(ReturnedExpression, RequestedType);
            } 
        }
    }

    ///  
    /// For collection results, we really want to know the expression to
    /// get the coordinator from its stateslot as well, so we have an 
    /// additional one... 
    /// 
    internal class CollectionTranslatorResult : TranslatorResult 
    {
        internal readonly Expression ExpressionToGetCoordinator;

        internal CollectionTranslatorResult(Expression returnedExpression, ColumnMap columnMap, Type requestedType, Expression expressionToGetCoordinator) 
            : base(returnedExpression, requestedType)
        { 
            this.ExpressionToGetCoordinator = expressionToGetCoordinator; 
        }
    } 

    /// 
    /// Translates query ColumnMap into ShaperFactory. Basically, we interpret the
    /// ColumnMap and compile delegates used to materialize results. 
    /// 
    internal class Translator : ColumnMapVisitorWithResults 
    { 
        #region private state
 
        /// 
        /// Gets the O-Space Metadata workspace.
        /// 
        private readonly MetadataWorkspace _workspace; 

        ///  
        /// Gets structure telling us how to interpret 'span' rows (includes implicit 
        /// relationship span and explicit full span via ObjectQuery.Include().
        ///  
        private readonly SpanIndex _spanIndex;

        /// 
        /// Gets the MergeOption for the current query (influences our handling of 
        /// entities when they are materialized).
        ///  
        private readonly MergeOption _mergeOption; 

        ///  
        /// When true, indicates we're processing for the value layer (BridgeDataReader)
        /// and not the ObjectMaterializer
        /// 
        private readonly bool IsValueLayer; 

        ///  
        /// Gets scratchpad for topmost nested reader coordinator. 
        /// 
        private CoordinatorScratchpad _rootCoordinatorScratchpad; 

        /// 
        /// Gets scratchpad for the coordinator builder for the nested reader currently
        /// being translated or emitted. 
        /// 
        private CoordinatorScratchpad _currentCoordinatorScratchpad; 
 
        /// 
        /// Gets number of 'Shaper.State' slots allocated (used to hold onto intermediate 
        /// values during materialization)
        /// 
        private int _stateSlotCount;
 
        /// 
        /// Set to true if any Entity/Complex type/property for which we're emitting a 
        /// handler is non-public. Used to determine which security checks are necessary 
        /// when invoking the delegate.
        ///  
        private bool _hasNonPublicMembers;

        /// 
        /// Keeps track of all LINQ expressions accepted from the user code. 
        /// 
        private readonly List>> _userExpressions = new List>>(); 
 
        /// 
        /// Local cache of ObjectTypeMappings for EdmTypes (to prevent expensive lookups). 
        /// 
        private readonly Dictionary _objectTypeMappings = new Dictionary();

        #endregion 

        #region constructor 
 
        private Translator(MetadataWorkspace workspace, SpanIndex spanIndex, MergeOption mergeOption, bool valueLayer)
        { 
            _workspace = workspace;
            _spanIndex = spanIndex;
            _mergeOption = mergeOption;
            IsValueLayer = valueLayer; 
        }
 
        #endregion 

        #region "public" surface area 

        /// 
        /// The main entry point for the translation process. Given a ColumnMap, returns
        /// a ShaperFactory which can be used to materialize results for a query. 
        /// 
        internal static ShaperFactory TranslateColumnMap(QueryCacheManager queryCacheManager, ColumnMap columnMap, MetadataWorkspace workspace, SpanIndex spanIndex, MergeOption mergeOption, bool valueLayer) 
        { 
            Debug.Assert(columnMap is CollectionColumnMap, "root column map must be a collection for a query");
 
            // If the query cache already contains a plan, then we're done
            ShaperFactory result;
            string columnMapKey = ColumnMapKeyBuilder.GetColumnMapKey(columnMap, spanIndex);
            ShaperFactoryQueryCacheKey cacheKey = new ShaperFactoryQueryCacheKey(columnMapKey, mergeOption, valueLayer); 

            if (queryCacheManager.TryCacheLookup(cacheKey, out result)) 
            { 
                return result;
            } 

            // Didn't find it in the cache, so we have to do the translation;  First create
            // the translator visitor that recursively tranforms ColumnMaps into Expressions
            // stored on the CoordinatorScratchpads it also constructs.  We'll compile those 
            // expressions into delegates later.
            Translator translator = new Translator(workspace, spanIndex, mergeOption, valueLayer); 
            columnMap.Accept(translator, new TranslatorArg(typeof(IEnumerable<>).MakeGenericType(typeof(TRequestedType)))); 

            Debug.Assert(null != translator._rootCoordinatorScratchpad, "translating the root of the query must populate _rootCoordinatorBuilder"); // how can this happen? 

            // We're good. Go ahead and recursively compile the CoordinatorScratchpads we
            // created in the vistor into CoordinatorFactories which contain compiled
            // delegates for the expressions we generated. 
            CoordinatorFactory coordinatorFactory = (CoordinatorFactory)translator._rootCoordinatorScratchpad.Compile();
 
            // Along the way we constructed a nice delegate to perform runtime permission 
            // checks (e.g. for LinkDemand and non-public members).  We need that now.
            Action checkPermissionsDelegate = translator.GetCheckPermissionsDelegate(); 

            // Finally, take everything we've produced, and create the ShaperFactory to
            // contain it all, then add it to the query cache so we don't need to do this
            // for this query again. 
            result = new ShaperFactory(translator._stateSlotCount, coordinatorFactory, checkPermissionsDelegate, mergeOption);
            QueryCacheEntry cacheEntry = new ShaperFactoryQueryCacheEntry(cacheKey, result); 
            if (queryCacheManager.TryLookupAndAdd(cacheEntry, out cacheEntry)) 
            {
                // Someone beat us to it. Use their result instead. 
                result = ((ShaperFactoryQueryCacheEntry)cacheEntry).GetTarget();
            }
            return result;
        } 

        ///  
        /// Compiles a delegate taking a Shaper instance and returning values. Used to compile 
        /// Expressions produced by the emitter.
        /// 
        /// Asserts MemberAccess to skip visbility check.
        /// This means that that security checks are skipped. Before calling this
        /// method you must ensure that you've done a TestComple on expressions provided
        /// by the user to ensure the compilation doesn't violate them. 
        /// 
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2128")] 
        [System.Security.SecuritySafeCritical] 
        [ReflectionPermission(SecurityAction.Assert, MemberAccess = true)]
        internal static Func Compile(Expression body) 
        {
            var lambda = Expression.Lambda>(body, Shaper_Parameter);
            return lambda.Compile();
        } 

        ///  
        /// Non-generic version of Compile (where the result type is passed in as an argument rather 
        /// than a type parameter)
        ///  
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)]
        internal static object Compile(Type resultType, Expression body)
        {
            MethodInfo compile = Translator_Compile.MakeGenericMethod(resultType); 
            return compile.Invoke(null, new object[] { body });
        } 
 
        /// 
        /// Tell the translator about a user-defined LINQ expression that is being inlined 
        /// in the materializer delegate.  Before we produce the shaper factory we'll ensure
        /// that security is not violated by using this expression in our delegates.
        /// 
        internal void RegisterUserExpression(Expression expression) 
        {
            Expression> lambda = Expression.Lambda>(Expression.Convert(expression, typeof(object))); 
            _userExpressions.Add(lambda); 
        }
 
        #endregion

        #region helpers
 
        /// 
        /// Allocates a slot in 'Shaper.State' which can be used as storage for 
        /// materialization tasks (e.g. remembering key values for a nested collection) 
        /// 
        private int AllocateStateSlot() 
        {
            return _stateSlotCount++;
        }
 
        /// 
        /// Returns a delegate performing necessary permission checks identified 
        /// by this translator.  This delegate must be called every time a row is 
        /// read from the ObjectResult enumerator, since the enumerator can be
        /// passed across security contexts. 
        /// 
        private Action GetCheckPermissionsDelegate()
        {
            // Emit an action to check runtime permissions. 
            Action checkPermissions = null;
            if (_hasNonPublicMembers) 
            { 
                checkPermissions = DemandMemberAccess;
            } 
            else if (_userExpressions.Count > 0)
            {
                IEnumerable>> userExpressions = _userExpressions;
                checkPermissions = () => VerifyUserExpressions(userExpressions); 
            }
            return checkPermissions; 
        } 

        private static void DemandMemberAccess() 
        {
            LightweightCodeGenerator.MemberAccessReflectionPermission.Demand();
        }
 
        /// 
        /// Try compiling the user expressions to ensure it would succeed without an 
        /// assert (user expressions are inlined with references to EF internals which 
        /// require the assert so we need to check the user expressions separately).
        /// 
        /// This method is called every time a new query result is returned to make sure
        /// the user expressions can be compiled in the current security context.
        /// 
        private static void VerifyUserExpressions(IEnumerable>> userExpressions) 
        {
            // As an optimization, check if we have member access permission. If so, 
            // we know the compile would succeed and don't need to make the effort. 
            if (!LightweightCodeGenerator.HasMemberAccessReflectionPermission())
            { 
                // If we don't have MemberAccess, compile the expressions to see if they
                // might be satisfied by RestrictedMemberAccess.
                foreach (Expression> userExpression in userExpressions)
                { 
                    userExpression.Compile();
                } 
            } 
        }
 
        /// 
        /// Return the CLR type we're supposed to materialize for the TypeUsage
        /// 
        private Type DetermineClrType(TypeUsage typeUsage) 
        {
            return DetermineClrType(typeUsage.EdmType); 
        } 

        ///  
        /// Return the CLR type we're supposed to materialize for the EdmType
        /// 
        private Type DetermineClrType(EdmType edmType)
        { 
            Type result = null;
            // Normalize for spandex 
            edmType = ResolveSpanType(edmType); 

            switch (edmType.BuiltInTypeKind) 
            {
                case BuiltInTypeKind.EntityType:
                case BuiltInTypeKind.ComplexType:
                    if (IsValueLayer) 
                    {
                        result = typeof(RecordState); 
                    } 
                    else
                    { 
                        result = LookupObjectMapping(edmType).ClrType.ClrType;
                    }
                    break;
 
                case BuiltInTypeKind.RefType:
                    result = typeof(EntityKey); 
                    break; 

                case BuiltInTypeKind.CollectionType: 
                    if (IsValueLayer)
                    {
                        result = typeof(Coordinator);
                    } 
                    else
                    { 
                        EdmType edmElementType = ((CollectionType)edmType).TypeUsage.EdmType; 
                        result = DetermineClrType(edmElementType);
                        result = typeof(IEnumerable<>).MakeGenericType(result); 
                    }
                    break;

                case BuiltInTypeKind.PrimitiveType: 
                    result = ((PrimitiveType)edmType).ClrEquivalentType;
                    if (result.IsValueType) 
                    { 
                        result = typeof(Nullable<>).MakeGenericType(result);
                    } 
                    break;

                case BuiltInTypeKind.RowType:
                    if (IsValueLayer) 
                    {
                        result = typeof(RecordState); 
                    } 
                    else
                    { 
                        // LINQ has anonymous types that aren't going to show up in our
                        // metadata workspace, and we don't want to hydrate a record when
                        // we need an anonymous type.  ELINQ solves this by annotating the
                        // edmType with some additional information, which we'll pick up 
                        // here.
                        InitializerMetadata initializerMetadata = ((RowType)edmType).InitializerMetadata; 
                        if (null != initializerMetadata) 
                        {
                            result = initializerMetadata.ClrType; 
                        }
                        else
                        {
                            // Otherwise, by default, we'll give DbDataRecord results (the 
                            // user can also cast to IExtendedDataRecord)
                            result = typeof(DbDataRecord); 
                        } 
                    }
                    break; 

                default:
                    Debug.Fail(string.Format(CultureInfo.CurrentCulture, "The type {0} was not the expected scalar, enumeration, collection, structural, nominal, or reference type.", edmType.GetType()));
                    break; 
            }
            Debug.Assert(null != result, "no result?"); // just making sure we cover this in the switch statement. 
 
            return result;
        } 

        /// 
        /// Get the ConstructorInfo for the type specified, and ensure we keep track
        /// of any security requirements that the type has. 
        /// 
        private ConstructorInfo GetConstructor(Type type) 
        { 
            ConstructorInfo result = null;
            if (!type.IsAbstract) 
            {
                result = LightweightCodeGenerator.GetConstructorForType(type);

                // remember security requirements for this constructor 
                if (!LightweightCodeGenerator.IsPublic(result))
                { 
                    _hasNonPublicMembers = true; 
                }
            } 
            return result;
        }

        ///  
        /// Retrieves object mapping metadata for the given type. The first time a type
        /// is encountered, we cache the metadata to avoid repeating the work for every 
        /// row in result. 
        ///
        /// Caching at the materializer rather than workspace/metadata cache level optimizes 
        /// for transient types (including row types produced for span, LINQ initializations,
        /// collections and projections).
        /// 
        private ObjectTypeMapping LookupObjectMapping(EdmType edmType) 
        {
            Debug.Assert(null != edmType, "no edmType?"); // edmType must not be null. 
 
            ObjectTypeMapping result;
 
            EdmType resolvedType = ResolveSpanType(edmType);
            if (null == resolvedType)
            {
                resolvedType = edmType; 
            }
 
            if (!_objectTypeMappings.TryGetValue(resolvedType, out result)) 
            {
                result = Util.GetObjectMapping(resolvedType, _workspace); 
                _objectTypeMappings.Add(resolvedType, result);
            }
            return result;
        } 

        ///  
        /// Remove spanned info from the edmType 
        /// 
        ///  
        /// 
        private EdmType ResolveSpanType(EdmType edmType)
        {
            EdmType result = edmType; 

            switch (result.BuiltInTypeKind) 
            { 
                case BuiltInTypeKind.CollectionType:
                    // For collections, we have to edmType from the (potentially) spanned 
                    // element of the collection, then build a new Collection around it.
                    result = ResolveSpanType(((CollectionType)result).TypeUsage.EdmType);
                    if (null != result)
                    { 
                        result = new CollectionType(result);
                    } 
                    break; 

                case BuiltInTypeKind.RowType: 
                    // If there is a SpanMap, pick up the EdmType from the first column
                    // in the record, otherwise it's just the type we already have.
                    RowType rowType = (RowType)result;
                    if (null != _spanIndex && _spanIndex.HasSpanMap(rowType)) 
                    {
                        result = rowType.Members[0].TypeUsage.EdmType; 
                    } 
                    break;
            } 
            return result;
        }

        ///  
        /// Creates an expression representing an inline delegate of type Func<Shaper, body.Type>
        ///  
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] 
        private LambdaExpression CreateInlineDelegate(Expression body)
        { 
            // Note that we call through to a typed method so that we can call Expression.Lambda instead
            // of the straightforward Expression.Lambda. The latter requires FullTrust.
            Type delegateReturnType = body.Type;
            MethodInfo createMethod = Translator_TypedCreateInlineDelegate.MakeGenericMethod(delegateReturnType); 
            LambdaExpression result = (LambdaExpression)createMethod.Invoke(this, new object[] { body });
            return result; 
        } 

        private Expression> TypedCreateInlineDelegate(Expression body) 
        {
            Expression> result = Expression.Lambda>(body, Shaper_Parameter);
            _currentCoordinatorScratchpad.AddInlineDelegate(result);
            return result; 
        }
 
        #endregion 

        #region Lightweight CodeGen emitters 

        #region static Reflection info used in emitters

        private static readonly MethodInfo DbDataReader_GetValue = typeof(DbDataReader).GetMethod("GetValue"); 
        private static readonly MethodInfo DbDataReader_GetString = typeof(DbDataReader).GetMethod("GetString");
        private static readonly MethodInfo DbDataReader_GetInt16 = typeof(DbDataReader).GetMethod("GetInt16"); 
        private static readonly MethodInfo DbDataReader_GetInt32 = typeof(DbDataReader).GetMethod("GetInt32"); 
        private static readonly MethodInfo DbDataReader_GetInt64 = typeof(DbDataReader).GetMethod("GetInt64");
        private static readonly MethodInfo DbDataReader_GetBoolean = typeof(DbDataReader).GetMethod("GetBoolean"); 
        private static readonly MethodInfo DbDataReader_GetDecimal = typeof(DbDataReader).GetMethod("GetDecimal");
        private static readonly MethodInfo DbDataReader_GetFloat = typeof(DbDataReader).GetMethod("GetFloat");
        private static readonly MethodInfo DbDataReader_GetDouble = typeof(DbDataReader).GetMethod("GetDouble");
        private static readonly MethodInfo DbDataReader_GetDateTime = typeof(DbDataReader).GetMethod("GetDateTime"); 
        private static readonly MethodInfo DbDataReader_GetGuid = typeof(DbDataReader).GetMethod("GetGuid");
        private static readonly MethodInfo DbDataReader_GetByte = typeof(DbDataReader).GetMethod("GetByte"); 
        private static readonly MethodInfo DbDataReader_IsDBNull = typeof(DbDataReader).GetMethod("IsDBNull"); 

        private static readonly ConstructorInfo EntityKey_ctor_SingleKey = typeof(EntityKey).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(EntitySet), typeof(object) }, null); 
        private static readonly ConstructorInfo EntityKey_ctor_CompositeKey = typeof(EntityKey).GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance, null, new Type[] { typeof(EntitySet), typeof(object[]) }, null);

        private static readonly MethodInfo IEntityKeyWithKey_EntityKey = typeof(System.Data.Objects.DataClasses.IEntityWithKey).GetProperty("EntityKey").GetSetMethod();
 
        private static readonly MethodInfo IEqualityComparerOfString_Equals = typeof(IEqualityComparer).GetMethod("Equals", new Type[] { typeof(string), typeof(string) });
 
        private static readonly ConstructorInfo MaterializedDataRecord_ctor = typeof(MaterializedDataRecord).GetConstructor( 
                                                                                            BindingFlags.NonPublic | BindingFlags.Instance,
                                                                                            null, new Type[] { typeof(MetadataWorkspace), typeof(TypeUsage), typeof(object[]) }, 
                                                                                            null);

        private static readonly MethodInfo RecordState_GatherData = typeof(RecordState).GetMethod("GatherData", BindingFlags.NonPublic | BindingFlags.Instance);
        private static readonly MethodInfo RecordState_SetNullRecord = typeof(RecordState).GetMethod("SetNullRecord", BindingFlags.NonPublic | BindingFlags.Instance); 

        private static readonly MethodInfo Shaper_Discriminate = typeof(Shaper).GetMethod("Discriminate"); 
        private static readonly MethodInfo Shaper_GetPropertyValueWithErrorHandling = typeof(Shaper).GetMethod("GetPropertyValueWithErrorHandling"); 
        private static readonly MethodInfo Shaper_GetColumnValueWithErrorHandling = typeof(Shaper).GetMethod("GetColumnValueWithErrorHandling");
        private static readonly MethodInfo Shaper_HandleEntity = typeof(Shaper).GetMethod("HandleEntity"); 
        private static readonly MethodInfo Shaper_HandleEntityAppendOnly = typeof(Shaper).GetMethod("HandleEntityAppendOnly");
        private static readonly MethodInfo Shaper_HandleEntityNoTracking = typeof(Shaper).GetMethod("HandleEntityNoTracking");
        private static readonly MethodInfo Shaper_HandleFullSpanCollection = typeof(Shaper).GetMethod("HandleFullSpanCollection");
        private static readonly MethodInfo Shaper_HandleFullSpanElement = typeof(Shaper).GetMethod("HandleFullSpanElement"); 
        private static readonly MethodInfo Shaper_HandleIEntityWithKey = typeof(Shaper).GetMethod("HandleIEntityWithKey");
        private static readonly MethodInfo Shaper_HandleRelationshipSpan = typeof(Shaper).GetMethod("HandleRelationshipSpan"); 
        private static readonly MethodInfo Shaper_SetColumnValue = typeof(Shaper).GetMethod("SetColumnValue"); 
        private static readonly MethodInfo Shaper_SetEntityRecordInfo = typeof(Shaper).GetMethod("SetEntityRecordInfo");
        private static readonly MethodInfo Shaper_SetState = typeof(Shaper).GetMethod("SetState"); 
        private static readonly MethodInfo Shaper_SetStatePassthrough = typeof(Shaper).GetMethod("SetStatePassthrough");

        private static readonly MethodInfo Translator_BinaryEquals = typeof(Translator).GetMethod("BinaryEquals", BindingFlags.NonPublic | BindingFlags.Static);
        private static readonly MethodInfo Translator_CheckedConvert = typeof(Translator).GetMethod("CheckedConvert", BindingFlags.NonPublic | BindingFlags.Static); 
        private static readonly MethodInfo Translator_Compile = typeof(Translator).GetMethod("Compile", BindingFlags.NonPublic | BindingFlags.Static, null, new Type[] { typeof(Expression) }, null);
        private static readonly MethodInfo Translator_MultipleDiscriminatorPolymorphicColumnMapHelper = typeof(Translator).GetMethod("MultipleDiscriminatorPolymorphicColumnMapHelper", BindingFlags.NonPublic | BindingFlags.Instance); 
        private static readonly MethodInfo Translator_TypedCreateInlineDelegate = typeof(Translator).GetMethod("TypedCreateInlineDelegate", BindingFlags.NonPublic | BindingFlags.Instance); 

        private static readonly PropertyInfo EntityWrapperFactory_NullWrapper = typeof(EntityWrapperFactory).GetProperty("NullWrapper", BindingFlags.Static | BindingFlags.NonPublic); 
        private static readonly PropertyInfo IEntityWrapper_Entity = typeof(IEntityWrapper).GetProperty("Entity");
        private static readonly MethodInfo EntityProxyTypeInfo_SetEntityWrapper = typeof(EntityProxyTypeInfo).GetMethod("SetEntityWrapper", BindingFlags.NonPublic | BindingFlags.Instance);

        private static readonly ConstructorInfo PocoPropertyAccessorStrategy_ctor = typeof(PocoPropertyAccessorStrategy).GetConstructor(new Type[] { typeof(object) }); 
        private static readonly ConstructorInfo EntityWithChangeTrackerStrategy_ctor = typeof(EntityWithChangeTrackerStrategy).GetConstructor(new Type[] { typeof(IEntityWithChangeTracker) });
        private static readonly ConstructorInfo EntityWithKeyStrategy_ctor = typeof(EntityWithKeyStrategy).GetConstructor(new Type[] { typeof(IEntityWithKey) }); 
        private static readonly ConstructorInfo PocoEntityKeyStrategy_ctor = typeof(PocoEntityKeyStrategy).GetConstructor(new Type[0]); 
        private static readonly PropertyInfo SnapshotChangeTrackingStrategy_Instance = typeof(SnapshotChangeTrackingStrategy).GetProperty("Instance", BindingFlags.Static | BindingFlags.Public);
 
        private static readonly MethodInfo EntityWrapperFactory_GetPocoPropertyAccessorStrategyFunc = typeof(EntityWrapperFactory).GetMethod("GetPocoPropertyAccessorStrategyFunc", BindingFlags.NonPublic | BindingFlags.Static);
        private static readonly MethodInfo EntityWrapperFactory_GetNullPropertyAccessorStrategyFunc = typeof(EntityWrapperFactory).GetMethod("GetNullPropertyAccessorStrategyFunc", BindingFlags.NonPublic | BindingFlags.Static);
        private static readonly MethodInfo EntityWrapperFactory_GetEntityWithChangeTrackerStrategyFunc = typeof(EntityWrapperFactory).GetMethod("GetEntityWithChangeTrackerStrategyFunc", BindingFlags.NonPublic | BindingFlags.Static);
        private static readonly MethodInfo EntityWrapperFactory_GetSnapshotChangeTrackingStrategyFunc = typeof(EntityWrapperFactory).GetMethod("GetSnapshotChangeTrackingStrategyFunc", BindingFlags.NonPublic | BindingFlags.Static); 
        private static readonly MethodInfo EntityWrapperFactory_GetEntityWithKeyStrategyStrategyFunc = typeof(EntityWrapperFactory).GetMethod("GetEntityWithKeyStrategyStrategyFunc", BindingFlags.NonPublic | BindingFlags.Static);
        private static readonly MethodInfo EntityWrapperFactory_GetPocoEntityKeyStrategyFunc = typeof(EntityWrapperFactory).GetMethod("GetPocoEntityKeyStrategyFunc", BindingFlags.NonPublic | BindingFlags.Static); 
 
        #endregion
 
        #region static expressions used in emitters

        private static readonly Expression DBNull_Value = Expression.Constant(DBNull.Value, typeof(object));
 
        internal static readonly ParameterExpression Shaper_Parameter = Expression.Parameter(typeof(Shaper), "shaper");
        private static readonly ParameterExpression EntityParameter = Expression.Parameter(typeof(object), "entity"); 
 
        private static readonly Expression Shaper_Reader = Expression.Field(Shaper_Parameter, typeof(Shaper).GetField("Reader"));
        private static readonly Expression Shaper_Workspace = Expression.Field(Shaper_Parameter, typeof(Shaper).GetField("Workspace")); 
        private static readonly Expression Shaper_State = Expression.Field(Shaper_Parameter, typeof(Shaper).GetField("State"));
        private static readonly Expression Shaper_Context = Expression.Field(Shaper_Parameter, typeof(Shaper).GetField("Context"));
        private static readonly Expression Shaper_Context_Options = Expression.Property(Shaper_Context, typeof(ObjectContext).GetProperty("ContextOptions"));
        private static readonly Expression Shaper_ProxyCreationEnabled = Expression.Property(Shaper_Context_Options, typeof(ObjectContextOptions).GetProperty("ProxyCreationEnabled")); 

        #endregion 
 
        /// 
        /// Create expression to AndAlso the expressions and return the result. 
        /// 
        private static Expression Emit_AndAlso(IEnumerable operands)
        {
            Expression result = null; 
            foreach (Expression operand in operands)
            { 
                if (result == null) 
                {
                    result = operand; 
                }
                else
                {
                    result = Expression.AndAlso(result, operand); 
                }
            } 
            return result; 
        }
 
        /// 
        /// Create expression to bitwise-or the expressions and return the result.
        /// 
        private static Expression Emit_BitwiseOr(IEnumerable operands) 
        {
            Expression result = null; 
            foreach (Expression operand in operands) 
            {
                if (result == null) 
                {
                    result = operand;
                }
                else 
                {
                    result = Expression.Or(result, operand); 
                } 
            }
            return result; 
        }

        /// 
        /// Creates an expression with null value. If the given type cannot be assigned 
        /// a null value, we create a value that throws when materializing. We don't throw statically
        /// because we consistently defer type checks until materialization. 
        /// 
        /// See SQL BU 588980.
        ///  
        /// Type of null expression.
        /// Null expression.
        internal static Expression Emit_NullConstant(Type type)
        { 
            Expression nullConstant;
            EntityUtil.CheckArgumentNull(type, "type"); 
 
            // check if null can be assigned to the type
            if (type.IsClass || TypeSystem.IsNullableType(type)) 
            {
                // create the constant directly if it accepts null
                nullConstant = Expression.Constant(null, type);
            } 
            else
            { 
                // create (object)null and then cast to the type 
                nullConstant = Emit_EnsureType(Expression.Constant(null, typeof(object)), type);
            } 
            return nullConstant;
        }

        ///  
        /// Emits an expression that represnts a NullEntityWrapper instance.
        ///  
        /// The type of the null to be wrapped 
        /// An expression represnting a wrapped null
        internal static Expression Emit_WrappedNullConstant(Type type) 
        {
            return Expression.Property(null, EntityWrapperFactory_NullWrapper);
        }
 
        /// 
        /// Create expression that guarantees the input expression is of the specified 
        /// type; no Convert is added if the expression is already of the same type. 
        ///
        /// Internal because it is called from the TranslatorResult. 
        /// 
        internal static Expression Emit_EnsureType(Expression input, Type type)
        {
            Expression result = input; 
            if (input.Type != type && !typeof(IEntityWrapper).IsAssignableFrom(input.Type))
            { 
                if (type.IsAssignableFrom(input.Type)) 
                {
                    // simple convert, just to make sure static type checks succeed 
                    result = Expression.Convert(input, type);
                }
                else
                { 
                    // user is asking for the 'wrong' type... add exception handling
                    // in case of failure 
                    MethodInfo checkedConvertMethod = Translator_CheckedConvert.MakeGenericMethod(input.Type, type); 
                    result = Expression.Call(checkedConvertMethod, input);
                } 
            }
            return result;
        }
 
        /// 
        /// Uses Emit_EnsureType and then wraps the result in an IEntityWrapper instance. 
        ///  
        /// The expression that creates the entity to be wrapped
        /// Expression to read the entity key 
        /// Expression to read the entity set
        /// The type that was actuall requested by the client--may be object
        /// The type of the identity type of the entity being materialized--never a proxy type
        /// The actual type being materialized--may be a proxy type 
        /// Either NoTracking or AppendOnly depending on whether the entity is to be tracked
        /// If true, then a proxy is being created 
        /// An expression representing the IEntityWrapper for the new entity 
        internal static Expression Emit_EnsureTypeAndWrap(Expression input, Expression keyReader, Expression entitySetReader, Type requestedType, Type identityType, Type actualType, MergeOption mergeOption, bool isProxy)
        { 
            Expression result = Emit_EnsureType(input, requestedType); // Needed to ensure appropriate exception is thrown
            if (!requestedType.IsClass)
            {
                result = Emit_EnsureType(input, typeof(object)); 
            }
            result = Emit_EnsureType(result, actualType); // Needed to ensure appropriate type for wrapper constructor 
            return CreateEntityWrapper(result, keyReader, entitySetReader, actualType, identityType, mergeOption, isProxy); 
        }
 
        /// 
        /// Returns an expression that creates an IEntityWrapper approprioate for the type of entity being materialized.
        /// 
        private static Expression CreateEntityWrapper(Expression input, Expression keyReader, Expression entitySetReader, Type actualType, Type identityType, MergeOption mergeOption, bool isProxy) 
        {
            Expression result; 
            bool isIEntityWithKey = typeof(IEntityWithKey).IsAssignableFrom(actualType); 
            bool isIEntityWithRelationships = typeof(IEntityWithRelationships).IsAssignableFrom(actualType);
            bool isIEntityWithChangeTracker = typeof(IEntityWithChangeTracker).IsAssignableFrom(actualType); 
            if (isIEntityWithRelationships && isIEntityWithChangeTracker && isIEntityWithKey && !isProxy)
            {
                // This is the case where all our interfaces are implemented by the entity and we are not creating a proxy.
                // This is the case that absolutely must be kept fast.  It is a simple call to the wrapper constructor. 
                Type genericType = typeof(LightweightEntityWrapper<>).MakeGenericType(actualType);
                ConstructorInfo ci = genericType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null, 
                                                                new Type[] { actualType, typeof(EntityKey), typeof(EntitySet), typeof(ObjectContext), typeof(MergeOption), typeof(Type) }, null); 
                result = Expression.New(ci, input, keyReader, entitySetReader, Shaper_Context, Expression.Constant(mergeOption, typeof(MergeOption)), Expression.Constant(identityType, typeof(Type)));
            } 
            else
            {
                // This is the general case.  We choose various strategy objects based on the interfaces implemented and
                // whether or not we are creating a proxy. 
                // We pass in lambdas to create the strategy objects so that they can have the materialized entity as
                // a parameter while still being set in the wrapper constructor. 
                Expression propertyAccessorStrategy = !isIEntityWithRelationships || isProxy ? 
                                                      Expression.Call(EntityWrapperFactory_GetPocoPropertyAccessorStrategyFunc) :
                                                      Expression.Call(EntityWrapperFactory_GetNullPropertyAccessorStrategyFunc); 

                Expression keyStrategy = isIEntityWithKey ?
                                         Expression.Call(EntityWrapperFactory_GetEntityWithKeyStrategyStrategyFunc) :
                                         Expression.Call(EntityWrapperFactory_GetPocoEntityKeyStrategyFunc); 

                Expression changeTrackingStrategy = isIEntityWithChangeTracker ? 
                                                    Expression.Call(EntityWrapperFactory_GetEntityWithChangeTrackerStrategyFunc) : 
                                                    Expression.Call(EntityWrapperFactory_GetSnapshotChangeTrackingStrategyFunc);
 
                Type genericType = isIEntityWithRelationships ?
                                   typeof(EntityWrapperWithRelationships<>).MakeGenericType(actualType) :
                                   typeof(EntityWrapperWithoutRelationships<>).MakeGenericType(actualType);
 
                ConstructorInfo ci = genericType.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.CreateInstance, null,
                                                                new Type[] { actualType, typeof(EntityKey), typeof(EntitySet), typeof(ObjectContext), typeof(MergeOption), typeof(Type), 
                                                                             typeof(Func), typeof(Func), typeof(Func) }, null); 
                result = Expression.New(ci, input, keyReader, entitySetReader, Shaper_Context, Expression.Constant(mergeOption, typeof(MergeOption)), Expression.Constant(identityType, typeof(Type)),
                                        propertyAccessorStrategy, changeTrackingStrategy, keyStrategy); 
            }
            result = Expression.Convert(result, typeof(IEntityWrapper));
            return result;
        } 

        ///  
        /// Takes an expression that represents an IEntityWrapper instance and creates a new 
        /// expression that extracts the raw entity from this.
        ///  
        internal static Expression Emit_UnwrapAndEnsureType(Expression input, Type type)
        {
            return Translator.Emit_EnsureType(Expression.Property(input, IEntityWrapper_Entity), type);
        } 

        ///  
        /// Method that the generated expression calls when the types are not 
        /// assignable
        ///  
        private static TTarget CheckedConvert(TSource value)
        {
            checked
            { 
                try
                { 
                    return (TTarget)(object)value; 
                }
                catch (InvalidCastException) 
                {
                    Type valueType = value.GetType();

                    // In the case of CompensatingCollection, simply report IEnumerable in the 
                    // exception message because the user has no reason to know what the type represents.
                    if (valueType.IsGenericType && valueType.GetGenericTypeDefinition() == typeof(CompensatingCollection<>)) 
                    { 
                        valueType = typeof(IEnumerable<>).MakeGenericType(valueType.GetGenericArguments());
                    } 
                    throw EntityUtil.ValueInvalidCast(valueType, typeof(TTarget));
                }
                catch (NullReferenceException)
                { 
                    throw EntityUtil.ValueNullReferenceCast(typeof(TTarget));
                } 
            } 
        }
 
        /// 
        /// Create expression to compare the results of two expressions and return
        /// whether they are equal.  Note we have special case logic for byte arrays.
        ///  
        private static Expression Emit_Equal(Expression left, Expression right)
        { 
            Expression result; 
            Debug.Assert(left.Type == right.Type, "equals with different types");
            if (typeof(byte[]) == left.Type) 
            {
                result = Expression.Call(Translator_BinaryEquals, left, right);
            }
            else 
            {
                result = Expression.Equal(left, right); 
            } 
            return result;
        } 

        /// 
        /// Helper method used in expressions generated by Emit_Equal to perform a
        /// byte-by-byte comparison of two byte arrays.  There really ought to be 
        /// a way to do this in the framework but I'm unaware of it.
        ///  
        private static bool BinaryEquals(byte[] left, byte[] right) 
        {
            if (null == left) 
            {
                return null == right;
            }
            else if (null == right) 
            {
                return false; 
            } 
            if (left.Length != right.Length)
            { 
                return false;
            }
            for (int i = 0; i < left.Length; i++)
            { 
                if (left[i] != right[i])
                { 
                    return false; 
                }
            } 
            return true;
        }

        ///  
        /// Creates expression to construct an EntityKey. Assumes that both the key has
        /// a value (Emit_EntityKey_HasValue == true) and that the EntitySet has value 
        /// (EntitySet != null). 
        /// 
        private static Expression Emit_EntityKey_ctor(Translator translator, EntityIdentity entityIdentity, bool isForColumnValue, out Expression entitySetReader) 
        {
            Expression result;
            Expression setEntitySetStateSlotValue = null;
 
            // First build the expressions that read each value that comprises the EntityKey
            List keyReaders = new List(entityIdentity.Keys.Length); 
            for (int i = 0; i < entityIdentity.Keys.Length; i++) 
            {
                Expression keyReader = entityIdentity.Keys[i].Accept(translator, new TranslatorArg(typeof(object))).Expression; 
                keyReaders.Add(keyReader);
            }

            // Next build the expression that determines us the entitySet; how we do this differs 
            // depending on whether we have a simple or discriminated identity.
 
            SimpleEntityIdentity simpleEntityIdentity = entityIdentity as SimpleEntityIdentity; 
            if (null != simpleEntityIdentity)
            { 
                if (simpleEntityIdentity.EntitySet == null)
                {
                    // 'Free-floating' entities do not have entity keys.
                    entitySetReader = Expression.Constant(null, typeof(EntitySet)); 
                    return Expression.Constant(null, typeof(EntityKey));
                } 
                // For SimpleEntityIdentities, the entitySet expression is a constant 
                entitySetReader = Expression.Constant(simpleEntityIdentity.EntitySet, typeof(EntitySet));
            } 
            else
            {
                // For DiscriminatedEntityIdentities, the we have to search the EntitySetMap
                // for the matching discriminator value; we'll get the discriminator first, 
                // the compare them all in sequence.
                DiscriminatedEntityIdentity discriminatedEntityIdentity = (DiscriminatedEntityIdentity)entityIdentity; 
 
                Expression discriminator = discriminatedEntityIdentity.EntitySetColumnMap.Accept(translator, new TranslatorArg(typeof(int?))).Expression;
                EntitySet[] entitySets = discriminatedEntityIdentity.EntitySetMap; 

                //

 
                // (_discriminator == 0 ? entitySets[0] : (_discriminator == 1 ? entitySets[1] ... : null)
                entitySetReader = Expression.Constant(null, typeof(EntitySet)); 
                for (int i = 0; i < entitySets.Length; i++) 
                {
                    entitySetReader = Expression.Condition( 
                                                Expression.Equal(discriminator, Expression.Constant(i, typeof(int?))),
                                                Expression.Constant(entitySets[i], typeof(EntitySet)),
                                                entitySetReader
                                                ); 
                }
 
                // Allocate a stateSlot to contain the entitySet we determine, and ensure we 
                // store it there on the way to constructing the key.
                int entitySetStateSlotNumber = translator.AllocateStateSlot(); 
                setEntitySetStateSlotValue = Emit_Shaper_SetStatePassthrough(entitySetStateSlotNumber, entitySetReader);
                entitySetReader = Emit_Shaper_GetState(entitySetStateSlotNumber, typeof(EntitySet));
            }
 
            // And now that we have all the pieces, construct the EntityKey using the appropriate
            // constructor (there's an optimized constructor for the single key case) 
            if (1 == entityIdentity.Keys.Length) 
            {
                // new EntityKey(entitySet, keyReaders[0]) 
                result = Expression.New(EntityKey_ctor_SingleKey,
                                            entitySetReader,
                                            keyReaders[0]);
            } 
            else
            { 
                // new EntityKey(entitySet, { keyReaders[0], ... keyReaders[n] }) 
                result = Expression.New(EntityKey_ctor_CompositeKey,
                                            entitySetReader, 
                                            Expression.NewArrayInit(typeof(object), keyReaders));
            }

            // In the case where we've had to store the entitySetReader value in a 
            // state slot, we test the value for non-null before we construct the
            // entityKey.  We use this opportunity to stuff the value into the state 
            // slot, so the code above that attempts to read it from there will find 
            // it.
            if (null != setEntitySetStateSlotValue) 
            {
                Expression noEntityKeyExpression;
                if (translator.IsValueLayer && !isForColumnValue)
                { 
                    noEntityKeyExpression = Expression.Constant(EntityKey.NoEntitySetKey, typeof(EntityKey));
                } 
                else 
                {
                    noEntityKeyExpression = Expression.Constant(null, typeof(EntityKey)); 
                }
                result = Expression.Condition(
                                            Expression.Equal(setEntitySetStateSlotValue, Expression.Constant(null, typeof(EntitySet))),
                                            noEntityKeyExpression, 
                                            result
                                            ); 
            } 
            return result;
        } 

        /// 
        /// Create expression that verifies that the entityKey has a value.  Note we just
        /// presume that if the first key is non-null, all the keys will be valid. 
        /// 
        private static Expression Emit_EntityKey_HasValue(SimpleColumnMap[] keyColumns) 
        { 
            Debug.Assert(0 < keyColumns.Length, "empty keyColumns?");
 
            // !shaper.Reader.IsDBNull(keyColumn[0].ordinal)
            Expression result = Emit_Reader_IsDBNull(keyColumns[0]);
            result = Expression.Not(result);
            return result; 
        }
 
        ///  
        /// Create expression to call the specified Get method(ie: GetInt32, GetString, et al)
        /// of the shaper's source data reader 
        /// 
        private static Expression Emit_Reader_GetXXX(int ordinal, Type type, MethodInfo dataReaderMethod)
        {
            // (type)shaper.Reader.Get???(ordinal) 
            Expression result = Emit_EnsureType(Expression.Call(Shaper_Reader, dataReaderMethod, Expression.Constant(ordinal)), type);
            return result; 
        } 

        ///  
        /// Create expression to call the GetValue method of the shaper's source data reader
        /// 
        private static Expression Emit_Reader_GetValue(int ordinal, Type type)
        { 
            // (type)shaper.Reader.GetValue(ordinal)
            Expression result = Emit_EnsureType(Expression.Call(Shaper_Reader, DbDataReader_GetValue, Expression.Constant(ordinal)), type); 
            return result; 
        }
 
        /// 
        /// Create expression to call the IsDBNull method of the shaper's source data reader
        /// 
        private static Expression Emit_Reader_IsDBNull(int ordinal) 
        {
            // shaper.Reader.IsDBNull(ordinal) 
            Expression result = Expression.Call(Shaper_Reader, DbDataReader_IsDBNull, Expression.Constant(ordinal)); 
            return result;
        } 

        /// 
        /// Create expression to call the IsDBNull method of the shaper's source data reader
        /// for the scalar column represented by the column map. 
        /// 
        private static Expression Emit_Reader_IsDBNull(ColumnMap columnMap) 
        { 
            //
            Expression result = Emit_Reader_IsDBNull(((ScalarColumnMap)columnMap).ColumnPos); 
            return result;
        }

        ///  
        /// Create expression to read a property value with error handling
        ///  
        private static Expression Emit_Shaper_GetPropertyValueWithErrorHandling(Type propertyType, int ordinal, string propertyName, string typeName) 
        {
            // shaper.GetColumnValueWithErrorHandling(ordinal, propertyName, typeName) 
            Expression result = Expression.Call(Shaper_Parameter, Shaper_GetPropertyValueWithErrorHandling.MakeGenericMethod(propertyType), Expression.Constant(ordinal), Expression.Constant(propertyName), Expression.Constant(typeName));
            return result;
        }
 
        /// 
        /// Create expression to read a column value with error handling 
        ///  
        private static Expression Emit_Shaper_GetColumnValueWithErrorHandling(Type columnType, int ordinal)
        { 
            // shaper.GetColumnValueWithErrorHandling(ordinal, propertyName, typeName)
            Expression result = Expression.Call(Shaper_Parameter, Shaper_GetColumnValueWithErrorHandling.MakeGenericMethod(columnType), Expression.Constant(ordinal));
            return result;
        } 

        ///  
        /// Create expression to read an item from the shaper's state array 
        /// 
        private static Expression Emit_Shaper_GetState(int stateSlotNumber, Type type) 
        {
            // (type)shaper.State[stateSlotNumber]
            Expression result = Emit_EnsureType(Expression.ArrayIndex(Shaper_State, Expression.Constant(stateSlotNumber)), type);
            return result; 
        }
 
        ///  
        /// Create expression to set an item in the shaper's state array
        ///  
        private static Expression Emit_Shaper_SetState(int stateSlotNumber, Expression value)
        {
            // shaper.SetState(stateSlotNumber, value)
            Expression result = Expression.Call(Shaper_Parameter, Shaper_SetState.MakeGenericMethod(value.Type), Expression.Constant(stateSlotNumber), value); 
            return result;
        } 
 
        /// 
        /// Create expression to set an item in the shaper's state array 
        /// 
        private static Expression Emit_Shaper_SetStatePassthrough(int stateSlotNumber, Expression value)
        {
            // shaper.SetState(stateSlotNumber, value) 
            Expression result = Expression.Call(Shaper_Parameter, Shaper_SetStatePassthrough.MakeGenericMethod(value.Type), Expression.Constant(stateSlotNumber), value);
            return result; 
        } 
        #endregion
 
        #region ColumnMapVisitor implementation

        // utility accept that looks up CLR type
        private static TranslatorResult AcceptWithMappedType(Translator translator, ColumnMap columnMap, ColumnMap parent) 
        {
            Type type = translator.DetermineClrType(columnMap.Type); 
            TranslatorResult result = columnMap.Accept(translator, new TranslatorArg(type)); 
            return result;
        } 

        #region structured columns

        ///  
        /// Visit(ComplexTypeColumnMap)
        ///  
        internal override TranslatorResult Visit(ComplexTypeColumnMap columnMap, TranslatorArg arg) 
        {
            Expression result = null; 
            Expression nullSentinelCheck = null;

            if (null != columnMap.NullSentinel)
            { 
                nullSentinelCheck = Emit_Reader_IsDBNull(columnMap.NullSentinel);
            } 
 
            if (IsValueLayer)
            { 
                result = BuildExpressionToGetRecordState(columnMap, null, null, nullSentinelCheck);
            }
            else
            { 
                ComplexType complexType = (ComplexType)columnMap.Type.EdmType;
                Type clrType = DetermineClrType(complexType); 
                ConstructorInfo constructor = GetConstructor(clrType); 

                // Build expressions to read the property values from the source data 
                // reader and bind them to their target properties
                List propertyBindings = CreatePropertyBindings(columnMap, clrType, complexType.Properties);

                // We have all the property bindings now; go ahead and build the expression to 
                // construct the type and store the property values.
                result = Expression.MemberInit(Expression.New(constructor), propertyBindings); 
 
                // If there's a null sentinel, then everything above is gated upon whether
                // it's value is DBNull.Value. 
                if (null != nullSentinelCheck)
                {
                    // shaper.Reader.IsDBNull(nullsentinelOridinal) ? (type)null : result
                    result = Expression.Condition(nullSentinelCheck, Emit_NullConstant(result.Type), result); 
                }
            } 
            return new TranslatorResult(result, arg.RequestedType); 
        }
 
        /// 
        /// Visit(EntityColumnMap)
        /// 
        internal override TranslatorResult Visit(EntityColumnMap columnMap, TranslatorArg arg) 
        {
            Expression result; 
 
            // Build expressions to read the entityKey and determine the entitySet. Note
            // that we attempt to optimize things such that we won't construct anything 
            // that isn't needed, depending upon the interfaces the clrType derives from
            // and the MergeOption that was requested.
            //
            // We always need the entitySet, except when MergeOption.NoTracking 
            //
            // We always need the entityKey, except when MergeOption.NoTracking and the 
            // clrType doesn't derive from IEntityWithKey 
            EntityIdentity entityIdentity = columnMap.EntityIdentity;
            Expression entitySetReader = null; 
            Expression entityKeyReader = Emit_EntityKey_ctor(this, entityIdentity, false, out entitySetReader);

            if (IsValueLayer)
            { 
                Expression nullCheckExpression = Expression.Not(Emit_EntityKey_HasValue(entityIdentity.Keys));
                //Expression nullCheckExpression = Emit_EntityKey_HasValue(entityIdentity.Keys); 
                result = BuildExpressionToGetRecordState(columnMap, entityKeyReader, entitySetReader, nullCheckExpression); 
            }
            else 
            {
                Expression constructEntity = null;

                EntityType cSpaceType = (EntityType)columnMap.Type.EdmType; 
                Debug.Assert(cSpaceType.BuiltInTypeKind == BuiltInTypeKind.EntityType, "Type was " + cSpaceType.BuiltInTypeKind);
                ClrEntityType oSpaceType = (ClrEntityType)LookupObjectMapping(cSpaceType).ClrType; 
                Type clrType = oSpaceType.ClrType; 

                // Build expressions to read the property values from the source data 
                // reader and bind them to their target properties
                List propertyBindings = CreatePropertyBindings(columnMap, clrType, cSpaceType.Properties);

                // We have all the property bindings now; go ahead and build the expression to 
                // construct the entity or proxy and store the property values.  We'll wrap it with more
                // stuff that needs to happen (or not) below. 
                EntityProxyTypeInfo proxyTypeInfo = EntityProxyFactory.GetProxyType(oSpaceType); 

                // If no proxy type exists for the entity, construct the regular entity object. 
                // If a proxy type does exist, examine the ObjectContext.ContextOptions.ProxyCreationEnabled flag
                // to determine whether to create a regular or proxy entity object.

                Expression constructNonProxyEntity = Emit_ConstructEntity(oSpaceType, propertyBindings, entityKeyReader, entitySetReader, arg, null); 
                if (proxyTypeInfo == null)
                { 
                    constructEntity = constructNonProxyEntity; 
                }
                else 
                {
                    Expression constructProxyEntity = Emit_ConstructEntity(oSpaceType, propertyBindings, entityKeyReader, entitySetReader, arg, proxyTypeInfo);

                    constructEntity = Expression.Condition(Shaper_ProxyCreationEnabled, 
                                                           constructProxyEntity,
                                                           constructNonProxyEntity); 
                } 

                // If we're tracking, call HandleEntity (or HandleIEntityWithKey or 
                // HandleEntityAppendOnly) as appropriate
                if (MergeOption.NoTracking != _mergeOption)
                {
                    Type actualType = proxyTypeInfo == null ? clrType : proxyTypeInfo.ProxyType; 
                    if (typeof(IEntityWithKey).IsAssignableFrom(actualType) && MergeOption.AppendOnly != _mergeOption)
                    { 
                        constructEntity = Expression.Call(Shaper_Parameter, Shaper_HandleIEntityWithKey.MakeGenericMethod(clrType), 
                                                                                            constructEntity,
                                                                                            entitySetReader 
                                                                                            );
                    }
                    else
                    { 
                        if (MergeOption.AppendOnly == _mergeOption)
                        { 
                            // pass through a delegate creating the entity rather than the actual entity, so we can avoid 
                            // the cost of materialization when the entity is already in the state manager
 
                            //Func entityDelegate = shaper => constructEntity(shaper);
                            LambdaExpression entityDelegate = CreateInlineDelegate(constructEntity);
                            constructEntity = Expression.Call(Shaper_Parameter, Shaper_HandleEntityAppendOnly.MakeGenericMethod(clrType),
                                                                                            entityDelegate, 
                                                                                            entityKeyReader,
                                                                                            entitySetReader 
                                                                                            ); 
                        }
                        else 
                        {
                            constructEntity = Expression.Call(Shaper_Parameter, Shaper_HandleEntity.MakeGenericMethod(clrType),
                                                                                            constructEntity,
                                                                                            entityKeyReader, 
                                                                                            entitySetReader
                                                                                            ); 
                        } 
                    }
                } 
                else
                {
                    constructEntity = Expression.Call(Shaper_Parameter, Shaper_HandleEntityNoTracking.MakeGenericMethod(clrType),
                                                                                            constructEntity 
                                                                                            );
                } 
 
                // All the above is gated upon whether there really is an entity value;
                // we won't bother executing anything unless there is an entityKey value, 
                // otherwise we'll just return a typed null.
                result = Expression.Condition(
                                            Emit_EntityKey_HasValue(entityIdentity.Keys),
                                            constructEntity, 
                                            Emit_WrappedNullConstant(arg.RequestedType)
                                            ); 
            } 

            return new TranslatorResult(result, arg.RequestedType); 
        }

        private Expression Emit_ConstructEntity(EntityType oSpaceType, IEnumerable propertyBindings, Expression entityKeyReader, Expression entitySetReader, TranslatorArg arg, EntityProxyTypeInfo proxyTypeInfo)
        { 
            bool isProxy = proxyTypeInfo != null;
            Type clrType = oSpaceType.ClrType; 
            Type actualType; 

            Expression constructEntity; 

            if (isProxy)
            {
                constructEntity = Expression.MemberInit(Expression.New(proxyTypeInfo.ProxyType), propertyBindings); 
                actualType = proxyTypeInfo.ProxyType;
            } 
            else 
            {
                ConstructorInfo constructor = GetConstructor(clrType); 
                constructEntity = Expression.MemberInit(Expression.New(constructor), propertyBindings);
                actualType = clrType;
            }
 
            // After calling the constructor, immediately create an IEntityWrapper instance for the entity.
            constructEntity = Emit_EnsureTypeAndWrap(constructEntity, entityKeyReader, entitySetReader, arg.RequestedType, clrType, actualType, 
                                                     _mergeOption == MergeOption.NoTracking ? MergeOption.NoTracking : MergeOption.AppendOnly, isProxy); 

            if (isProxy) 
            {
                // Since we created a proxy, we now need to give it a reference to the wrapper that we just created.
                constructEntity = Expression.Call(Expression.Constant(proxyTypeInfo), EntityProxyTypeInfo_SetEntityWrapper, constructEntity);
 
                if (proxyTypeInfo.InitializeEntityCollections != null)
                { 
                    constructEntity = Expression.Call(proxyTypeInfo.InitializeEntityCollections, constructEntity); 
                }
            } 

            return constructEntity;
        }
 
        /// 
        /// Prepare a list of PropertyBindings for each item in the specified property 
        /// collection such that the mapped property of the specified clrType has its 
        /// value set from the source data reader.
        /// 
        /// Along the way we'll keep track of non-public properties and properties that
        /// have link demands, so we can ensure enforce them.
        /// 
        private List CreatePropertyBindings(StructuredColumnMap columnMap, Type clrType, ReadOnlyMetadataCollection properties) 
        {
            List result = new List(columnMap.Properties.Length); 
 
            ObjectTypeMapping mapping = LookupObjectMapping(columnMap.Type.EdmType);
 
            for (int i = 0; i < columnMap.Properties.Length; i++)
            {
                EdmProperty edmProperty = mapping.GetPropertyMap(properties[i].Name).ClrProperty;
 
                // get MethodInfo for setter
                MethodInfo propertyAccessor; 
                Type propertyType; 
                LightweightCodeGenerator.ValidateSetterProperty(edmProperty.EntityDeclaringType, edmProperty.PropertySetterHandle, out propertyAccessor, out propertyType);
 
                // determine if any security checks are required
                if (!LightweightCodeGenerator.IsPublic(propertyAccessor))
                {
                    _hasNonPublicMembers = true; 
                }
 
                // get translation of property value 
                Expression valueReader = columnMap.Properties[i].Accept(this, new TranslatorArg(propertyType)).Expression;
 
                ScalarColumnMap scalarColumnMap = columnMap.Properties[i] as ScalarColumnMap;
                if (null != scalarColumnMap)
                {
                    string propertyName = propertyAccessor.Name.Substring(4); // substring to strip "set_" 

                    // create a value reader with error handling 
                    Expression valueReaderWithErrorHandling = Emit_Shaper_GetPropertyValueWithErrorHandling(propertyType, scalarColumnMap.ColumnPos, propertyName, propertyAccessor.DeclaringType.Name); 
                    _currentCoordinatorScratchpad.AddExpressionWithErrorHandling(valueReader, valueReaderWithErrorHandling);
                } 

                Type entityDeclaringType = Type.GetTypeFromHandle(edmProperty.EntityDeclaringType);
                MemberBinding binding = Expression.Bind(GetProperty(propertyAccessor, entityDeclaringType), valueReader);
                result.Add(binding); 
            }
            return result; 
        } 

        ///  
        /// Gets the PropertyInfo representing the property with which the given setter method is associated.
        /// This code is taken from Expression.Bind(MethodInfo) but adapted to take a type such that it
        /// will work in cases in which the property was declared on a generic base class.  In such cases,
        /// the declaringType needs to be the actual entity type, rather than the base class type.  Note that 
        /// declaringType can be null, in which case the setterMethod.DeclaringType is used.
        ///  
        private static PropertyInfo GetProperty(MethodInfo setterMethod, Type declaringType) 
        {
            if (declaringType == null) 
            {
                declaringType = setterMethod.DeclaringType;
            }
            BindingFlags bindingAttr = BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance; 
            foreach (PropertyInfo propertyInfo in declaringType.GetProperties(bindingAttr))
            { 
                if (propertyInfo.GetSetMethod(nonPublic: true) == setterMethod) 
                {
                    return propertyInfo; 
                }
            }
            Debug.Fail("Should always find a property for the setterMethod since we got the setter method from a property in the first place.");
            return null; 
        }
 
        ///  
        /// Visit(SimplePolymorphicColumnMap)
        ///  
        internal override TranslatorResult Visit(SimplePolymorphicColumnMap columnMap, TranslatorArg arg)
        {
            Expression result;
 
            // We're building a conditional ladder, where we'll compare each
            // discriminator value with the one from the source data reader, and 
            // we'll pick that type if they match. 
            Expression discriminatorReader = AcceptWithMappedType(this, columnMap.TypeDiscriminator, columnMap).Expression;
 
            if (IsValueLayer)
            {
                result = Emit_EnsureType(
                                BuildExpressionToGetRecordState(columnMap, null, null, Expression.Constant(true)), 
                                arg.RequestedType);
            } 
            else 
            {
                result = Emit_WrappedNullConstant(arg.RequestedType); // the default 
            }

            foreach (var typeChoice in columnMap.TypeChoices)
            { 
                // determine CLR type for the type choice, and don't bother adding
                // this choice if it can't produce a result 
                Type type = DetermineClrType(typeChoice.Value.Type); 

                if (type.IsAbstract) 
                {
                    continue;
                }
 
                Expression discriminatorConstant = Expression.Constant(typeChoice.Key, discriminatorReader.Type);
                Expression discriminatorMatches; 
 
                // For string types, we have to use a specific comparison that handles
                // trailing spaces properly, not just the general equality test we use 
                // elsewhere.
                if (discriminatorReader.Type == typeof(string))
                {
                    discriminatorMatches = Expression.Call(Expression.Constant(TrailingSpaceStringComparer.Instance), IEqualityComparerOfString_Equals, discriminatorConstant, discriminatorReader); 
                }
                else 
                { 
                    discriminatorMatches = Emit_Equal(discriminatorConstant, discriminatorReader);
                } 

                result = Expression.Condition(discriminatorMatches,
                                            typeChoice.Value.Accept(this, arg).Expression,
                                            result); 

            } 
            return new TranslatorResult(result, arg.RequestedType); 
        }
 
        /// 
        /// Visit(MultipleDiscriminatorPolymorphicColumnMap)
        /// 
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] 
        internal override TranslatorResult Visit(MultipleDiscriminatorPolymorphicColumnMap columnMap, TranslatorArg arg)
        { 
            MethodInfo multipleDiscriminatorPolymorphicColumnMapHelper = Translator_MultipleDiscriminatorPolymorphicColumnMapHelper.MakeGenericMethod(arg.RequestedType); 
            Expression result = (Expression)multipleDiscriminatorPolymorphicColumnMapHelper.Invoke(this, new object[] { columnMap, arg });
            return new TranslatorResult(result, arg.RequestedType); 
        }

        /// 
        /// Helper method to simplify the construction of the types; I'm just too lazy to 
        /// create all the nested generic types needed to this by hand.
        ///  
        private Expression MultipleDiscriminatorPolymorphicColumnMapHelper(MultipleDiscriminatorPolymorphicColumnMap columnMap, TranslatorArg arg) 
        {
            // construct an array of discriminator values 
            Expression[] discriminatorReaders = new Expression[columnMap.TypeDiscriminators.Length];
            for (int i = 0; i < discriminatorReaders.Length; i++)
            {
                discriminatorReaders[i] = columnMap.TypeDiscriminators[i].Accept(this, new TranslatorArg(typeof(object))).Expression; 
            }
            Expression discriminatorValues = Expression.NewArrayInit(typeof(object), discriminatorReaders); 
 
            // Next build the expressions that will construct the type choices. An array of KeyValuePair>
            List elementDelegates = new List(); 
            Type typeDelegatePairType = typeof(KeyValuePair>);
            ConstructorInfo typeDelegatePairConstructor = typeDelegatePairType.GetConstructor(new Type[] { typeof(EntityType), typeof(Func) });
            foreach (var typeChoice in columnMap.TypeChoices)
            { 
                Expression typeReader = Emit_EnsureType(AcceptWithMappedType(this, typeChoice.Value, columnMap).UnwrappedExpression, typeof(TElement));
                LambdaExpression typeReaderDelegate = CreateInlineDelegate(typeReader); 
                Expression typeDelegatePair = Expression.New( 
                                                    typeDelegatePairConstructor,
                                                    Expression.Constant(typeChoice.Key), 
                                                    typeReaderDelegate
                                                    );
                elementDelegates.Add(typeDelegatePair);
            } 

            // invoke shaper.Discrimate({ discriminatorValue1...discriminatorValueN }, discriminateDelegate, elementDelegates) 
            MethodInfo shaperDiscriminateOfT = Shaper_Discriminate.MakeGenericMethod(typeof(TElement)); 
            Expression result = Expression.Call(Shaper_Parameter, shaperDiscriminateOfT,
                                                    discriminatorValues, 
                                                    Expression.Constant(columnMap.Discriminate),
                                                    Expression.NewArrayInit(typeDelegatePairType, elementDelegates)
                                                    );
            return result; 
        }
 
        ///  
        /// Visit(RecordColumnMap)
        ///  
        internal override TranslatorResult Visit(RecordColumnMap columnMap, TranslatorArg arg)
        {
            Expression result = null;
            Expression nullSentinelCheck = null; 

            if (null != columnMap.NullSentinel) 
            { 
                nullSentinelCheck = Emit_Reader_IsDBNull(columnMap.NullSentinel);
            } 

            if (IsValueLayer)
            {
                result = BuildExpressionToGetRecordState(columnMap, null, null, nullSentinelCheck); 
            }
            else 
            { 
                Debug.Assert(columnMap.Type.EdmType.BuiltInTypeKind == BuiltInTypeKind.RowType, "RecordColumnMap without RowType?"); // we kind of depend upon this
                Expression nullConstant; 

                // There are (at least) three different reasons we have a RecordColumnMap
                // so pick the method that handles the reason we have for this one.
                InitializerMetadata initializerMetadata; 
                if (InitializerMetadata.TryGetInitializerMetadata(columnMap.Type, out initializerMetadata))
                { 
                    result = HandleLinqRecord(columnMap, initializerMetadata); 
                    nullConstant = Emit_NullConstant(result.Type);
                } 
                else
                {
                    RowType spanRowType = (RowType)columnMap.Type.EdmType;
 
                    if (null != _spanIndex && _spanIndex.HasSpanMap(spanRowType))
                    { 
                        result = HandleSpandexRecord(columnMap, arg, spanRowType); 
                        nullConstant = Emit_WrappedNullConstant(result.Type);
                    } 
                    else
                    {
                        result = HandleRegularRecord(columnMap, arg, spanRowType);
                        nullConstant = Emit_NullConstant(result.Type); 
                    }
                } 
 
                // If there is a null sentinel process it accordingly.
                if (null != nullSentinelCheck) 
                {
                    // shaper.Reader.IsDBNull(nullsentinelOridinal) ? (type)null : result
                    result = Expression.Condition(nullSentinelCheck, nullConstant, result);
                } 
            }
            return new TranslatorResult(result, arg.RequestedType); 
        } 

        private Expression BuildExpressionToGetRecordState(StructuredColumnMap columnMap, Expression entityKeyReader, Expression entitySetReader, Expression nullCheckExpression) 
        {
            RecordStateScratchpad recordStateScratchpad = _currentCoordinatorScratchpad.CreateRecordStateScratchpad();

            int stateSlotNumber = AllocateStateSlot(); 
            recordStateScratchpad.StateSlotNumber = stateSlotNumber;
 
            int propertyCount = columnMap.Properties.Length; 
            int readerCount = (null != entityKeyReader) ? propertyCount + 1 : propertyCount;
 
            recordStateScratchpad.ColumnCount = propertyCount;

            // We can have an entity here, even though it's a RecordResultColumn, because
            // it may be a polymorphic type; eg: TREAT(Product AS DiscontinuedProduct); we 
            // construct an EntityRecordInfo with a sentinel EntityNotValidKey as it's Key
            EntityType entityTypeMetadata = null; 
            if (TypeHelpers.TryGetEdmType(columnMap.Type, out entityTypeMetadata)) 
            {
                recordStateScratchpad.DataRecordInfo = new EntityRecordInfo(entityTypeMetadata, EntityKey.EntityNotValidKey, null); 
            }
            else
            {
                TypeUsage edmType = Helper.GetModelTypeUsage(columnMap.Type); 
                recordStateScratchpad.DataRecordInfo = new DataRecordInfo(edmType);
            } 
 
            Expression[] propertyReaders = new Expression[readerCount];
            string[] propertyNames = new string[recordStateScratchpad.ColumnCount]; 
            TypeUsage[] typeUsages = new TypeUsage[recordStateScratchpad.ColumnCount];

            for (int ordinal = 0; ordinal < propertyCount; ordinal++)
            { 
                Expression propertyReader = columnMap.Properties[ordinal].Accept(this, new TranslatorArg(typeof(Object))).Expression;
 
                // recordState.SetColumnValue(i, propertyReader ?? DBNull.Value) 
                propertyReaders[ordinal] = Expression.Call(Shaper_Parameter, Shaper_SetColumnValue,
                                                        Expression.Constant(stateSlotNumber), 
                                                        Expression.Constant(ordinal),
                                                        Expression.Coalesce(propertyReader, DBNull_Value)
                                                    );
 
                propertyNames[ordinal] = columnMap.Properties[ordinal].Name;
                typeUsages[ordinal] = columnMap.Properties[ordinal].Type; 
            } 

            if (null != entityKeyReader) 
            {
                propertyReaders[readerCount - 1] = Expression.Call(Shaper_Parameter, Shaper_SetEntityRecordInfo,
                                                        Expression.Constant(stateSlotNumber),
                                                        entityKeyReader, 
                                                        entitySetReader);
            } 
 
            recordStateScratchpad.GatherData = Emit_BitwiseOr(propertyReaders);
            recordStateScratchpad.PropertyNames = propertyNames; 
            recordStateScratchpad.TypeUsages = typeUsages;

            // Finally, build the expression to read the recordState from the shaper state
 
            // (RecordState)shaperState.State[stateSlotNumber].GatherData(shaper)
            Expression result = Expression.Call(Emit_Shaper_GetState(stateSlotNumber, typeof(RecordState)), RecordState_GatherData, Shaper_Parameter); 
 
            // If there's a null check, then everything above is gated upon whether
            // it's value is DBNull.Value. 
            if (null != nullCheckExpression)
            {
                Expression nullResult = Expression.Call(Emit_Shaper_GetState(stateSlotNumber, typeof(RecordState)), RecordState_SetNullRecord, Shaper_Parameter);
                // nullCheckExpression ? (type)null : result 
                result = Expression.Condition(nullCheckExpression, nullResult, result);
            } 
            return result; 
        }
 
        /// 
        /// Build expression to materialize LINQ initialization types (anonymous
        /// types, IGrouping, EntityCollection)
        ///  
        private Expression HandleLinqRecord(RecordColumnMap columnMap, InitializerMetadata initializerMetadata)
        { 
            List propertyReaders = new List(columnMap.Properties.Length); 

            foreach (var pair in columnMap.Properties.Zip(initializerMetadata.GetChildTypes())) 
            {
                ColumnMap propertyColumnMap = pair.Key;
                Type type = pair.Value;
 
                // Note that we're not just blindly using the type from the column map
                // because we need to match the type thatthe initializer says it needs; 
                // that's why were not using AcceptWithMappedType; 
                if (null == type)
                { 
                    type = DetermineClrType(propertyColumnMap.Type);
                }

                TranslatorResult propertyReader = propertyColumnMap.Accept(this, new TranslatorArg(type)); 
                propertyReaders.Add(propertyReader);
            } 
 
            Expression result = initializerMetadata.Emit(this, propertyReaders);
            return result; 
        }

        /// 
        /// Build expression to materialize a data record. 
        /// 
        private Expression HandleRegularRecord(RecordColumnMap columnMap, TranslatorArg arg, RowType spanRowType) 
        { 
            // handle regular records
 
            // Build an array of expressions that read the individual values from the
            // source data reader.
            Expression[] columnReaders = new Expression[columnMap.Properties.Length];
            for (int i = 0; i < columnReaders.Length; i++) 
            {
                Expression columnReader = AcceptWithMappedType(this, columnMap.Properties[i], columnMap).UnwrappedExpression; 
 
                // ((object)columnReader) ?? DBNull.Value
                columnReaders[i] = Expression.Coalesce(Emit_EnsureType(columnReader, typeof(object)), DBNull_Value); 
            }
            // new object[] {columnReader0..columnReaderN}
            Expression columnReaderArray = Expression.NewArrayInit(typeof(object), columnReaders);
 

            // Get an expression representing the TypeUsage of the MaterializedDataRecord 
            // we're about to construct; we need to remove the span information from it, 
            // though, since we don't want to surface that...
            TypeUsage type = columnMap.Type; 
            if (null != _spanIndex)
            {
                type = _spanIndex.GetSpannedRowType(spanRowType) ?? type;
            } 
            Expression typeUsage = Expression.Constant(type, typeof(TypeUsage));
 
            // new MaterializedDataRecord(Shaper.Workspace, typeUsage, values) 
            Expression result = Emit_EnsureType(Expression.New(MaterializedDataRecord_ctor, Shaper_Workspace, typeUsage, columnReaderArray), arg.RequestedType);
            return result; 
        }

        /// 
        /// Build expression to materialize the spanned information 
        /// 
        private Expression HandleSpandexRecord(RecordColumnMap columnMap, TranslatorArg arg, RowType spanRowType) 
        { 
            Dictionary spanMap = _spanIndex.GetSpanMap(spanRowType);
 
            // First, build the expression to materialize the root item.
            Expression result = columnMap.Properties[0].Accept(this, arg).Expression;

            // Now build expressions that call into the appropriate shaper method 
            // for the type of span for each spanned item.
            for (int i = 1; i < columnMap.Properties.Length; i++) 
            { 
                AssociationEndMember targetMember = spanMap[i];
                TranslatorResult propertyTranslatorResult = AcceptWithMappedType(this, columnMap.Properties[i], columnMap); 
                Expression spannedResultReader = propertyTranslatorResult.Expression;

                // figure out the flavor of the span
                CollectionTranslatorResult collectionTranslatorResult = propertyTranslatorResult as CollectionTranslatorResult; 
                if (null != collectionTranslatorResult)
                { 
                    Expression expressionToGetCoordinator = collectionTranslatorResult.ExpressionToGetCoordinator; 

                    // full span collection 
                    Type elementType = spannedResultReader.Type.GetGenericArguments()[0];

                    MethodInfo handleFullSpanCollectionMethod = Shaper_HandleFullSpanCollection.MakeGenericMethod(arg.RequestedType, elementType);
                    result = Expression.Call(Shaper_Parameter, handleFullSpanCollectionMethod, result, expressionToGetCoordinator, Expression.Constant(targetMember)); 
                }
                else 
                { 
                    if (typeof(EntityKey) == spannedResultReader.Type)
                    { 
                        // relationship span
                        MethodInfo handleRelationshipSpanMethod = Shaper_HandleRelationshipSpan.MakeGenericMethod(arg.RequestedType);
                        result = Expression.Call(Shaper_Parameter, handleRelationshipSpanMethod, result, spannedResultReader, Expression.Constant(targetMember));
                    } 
                    else
                    { 
                        // full span element 
                        MethodInfo handleFullSpanElementMethod = Shaper_HandleFullSpanElement.MakeGenericMethod(arg.RequestedType, spannedResultReader.Type);
                        result = Expression.Call(Shaper_Parameter, handleFullSpanElementMethod, result, spannedResultReader, Expression.Constant(targetMember)); 
                    }
                }
            }
            return result; 
        }
 
        #endregion 

        #region collection columns 

        /// 
        /// Visit(SimpleCollectionColumnMap)
        ///  
        internal override TranslatorResult Visit(SimpleCollectionColumnMap columnMap, TranslatorArg arg)
        { 
            return ProcessCollectionColumnMap(columnMap, arg); 
        }
 
        /// 
        /// Visit(DiscriminatedCollectionColumnMap)
        /// 
        internal override TranslatorResult Visit(DiscriminatedCollectionColumnMap columnMap, TranslatorArg arg) 
        {
            return ProcessCollectionColumnMap(columnMap, arg, columnMap.Discriminator, columnMap.DiscriminatorValue); 
        } 

        ///  
        /// Common code for both Simple and Discrminated Column Maps.
        /// 
        private TranslatorResult ProcessCollectionColumnMap(CollectionColumnMap columnMap, TranslatorArg arg)
        { 
            return ProcessCollectionColumnMap(columnMap, arg, null, null);
        } 
 
        /// 
        /// Common code for both Simple and Discrminated Column Maps. 
        /// 
        private TranslatorResult ProcessCollectionColumnMap(CollectionColumnMap columnMap, TranslatorArg arg, ColumnMap discriminatorColumnMap, object discriminatorValue)
        {
            Type elementType = DetermineElementType(arg.RequestedType, columnMap); 

            // CoordinatorScratchpad aggregates information about the current nested 
            // result (represented by the given CollectionColumnMap) 
            CoordinatorScratchpad coordinatorScratchpad = new CoordinatorScratchpad(elementType);
 
            // enter scope for current coordinator when translating children, etc.
            EnterCoordinatorTranslateScope(coordinatorScratchpad);

 
            ColumnMap elementColumnMap = columnMap.Element;
 
            if (IsValueLayer) 
            {
                StructuredColumnMap structuredElement = elementColumnMap as StructuredColumnMap; 

                // If we have a collection of non-structured types we have to put
                // a structure around it, because we don't have data readers of
                // scalars, only structures.  We don't need a null sentinel because 
                // this structure can't ever be null.
                if (null == structuredElement) 
                { 
                    ColumnMap[] columnMaps = new ColumnMap[1] { columnMap.Element };
                    elementColumnMap = new RecordColumnMap(columnMap.Element.Type, columnMap.Element.Name, columnMaps, null); 
                }
            }

            // Build the expression that will construct the element of the collection 
            // from the source data reader.
            // We use UnconvertedExpression here so we can defer doing type checking in case 
            // we need to translate to a POCO collection later in the process. 
            Expression elementReader = elementColumnMap.Accept(this, new TranslatorArg(elementType)).UnconvertedExpression;
 
            // Build the expression(s) that read the collection's keys from the source
            // data reader; note that the top level collection may not have keys if there
            // are no children.
            Expression[] keyReaders; 

            if (null != columnMap.Keys) 
            { 
                keyReaders = new Expression[columnMap.Keys.Length];
                for (int i = 0; i < keyReaders.Length; i++) 
                {
                    Expression keyReader = AcceptWithMappedType(this, columnMap.Keys[i], columnMap).Expression;
                    keyReaders[i] = keyReader;
                } 
            }
            else 
            { 
                keyReaders = new Expression[] { };
            } 

            // Build the expression that reads the discriminator value from the source
            // data reader.
            Expression discriminatorReader = null; 
            if (null != discriminatorColumnMap)
            { 
                discriminatorReader = AcceptWithMappedType(this, discriminatorColumnMap, columnMap).Expression; 
            }
 
            // get expression retrieving the coordinator
            Expression expressionToGetCoordinator = BuildExpressionToGetCoordinator(elementType, elementReader, keyReaders, discriminatorReader, discriminatorValue, coordinatorScratchpad);
            MethodInfo getElementsExpression = typeof(Coordinator<>).MakeGenericType(elementType).GetMethod("GetElements", BindingFlags.NonPublic | BindingFlags.Instance);
 
            Expression result;
            if (IsValueLayer) 
            { 
                result = expressionToGetCoordinator;
            } 
            else
            {
                // coordinator.GetElements()
                result = Expression.Call(expressionToGetCoordinator, getElementsExpression); 

                // Perform the type check that was previously deferred so we could process POCO collections. 
                coordinatorScratchpad.Element = Emit_EnsureType(coordinatorScratchpad.Element, elementType); 

                // When materializing specifically requested collection types, we need 
                // to transfer the results from the Enumerable to the requested collection.
                Type innerElementType;
                if (EntityUtil.TryGetICollectionElementType(arg.RequestedType, out innerElementType))
                { 
                    // Given we have some type that implements ICollection, we need to decide what concrete
                    // collection type to instantiate--See EntityUtil.DetermineCollectionType for details. 
                    var typeToInstantiate = EntityUtil.DetermineCollectionType(arg.RequestedType); 

                    if (typeToInstantiate == null) 
                    {
                        throw EntityUtil.InvalidOperation(Strings.ObjectQuery_UnableToMaterializeArbitaryProjectionType(arg.RequestedType));
                    }
 
                    Type listOfElementType = typeof(List<>).MakeGenericType(innerElementType);
                    if (typeToInstantiate != listOfElementType) 
                    { 
                        coordinatorScratchpad.InitializeCollection = Emit_EnsureType(
                            Expression.New(GetConstructor(typeToInstantiate)), 
                            typeof(ICollection<>).MakeGenericType(innerElementType));
                    }
                    result = Emit_EnsureType(result, arg.RequestedType);
                } 
                else
                { 
                    // If any compensation is required (returning IOrderedEnumerable, not 
                    // just vanilla IEnumerable we must wrap the result with a static class
                    // that is of the type expected. 
                    if (!arg.RequestedType.IsAssignableFrom(result.Type))
                    {
                        // new CompensatingCollection(_collectionReader)
                        Type compensatingCollectionType = typeof(CompensatingCollection<>).MakeGenericType(elementType); 
                        ConstructorInfo constructorInfo = compensatingCollectionType.GetConstructors()[0];
                        result = Emit_EnsureType(Expression.New(constructorInfo, result), compensatingCollectionType); 
                    } 
                }
            } 
            ExitCoordinatorTranslateScope();
            return new CollectionTranslatorResult(result, columnMap, arg.RequestedType, expressionToGetCoordinator);
        }
 
        /// 
        /// Returns the CLR Type of the element of the collection 
        ///  
        private Type DetermineElementType(Type collectionType, CollectionColumnMap columnMap)
        { 
            Type result = null;

            if (IsValueLayer)
            { 
                result = typeof(RecordState);
            } 
            else 
            {
                result = TypeSystem.GetElementType(collectionType); 

                // GetElementType returns the input type if it is not a collection.
                if (result == collectionType)
                { 
                    // if the user isn't asking for a CLR collection type (e.g. ObjectQuery("{{1, 2}}")), we choose for them
                    TypeUsage edmElementType = ((CollectionType)columnMap.Type.EdmType).TypeUsage; // the TypeUsage of the Element of the collection. 
                    result = DetermineClrType(edmElementType); 
                }
            } 
            return result;
        }

        ///  
        /// Build up the coordinator graph using Enter/ExitCoordinatorTranslateScope.
        ///  
        private void EnterCoordinatorTranslateScope(CoordinatorScratchpad coordinatorScratchpad) 
        {
            if (null == _rootCoordinatorScratchpad) 
            {
                coordinatorScratchpad.Depth = 0;
                _rootCoordinatorScratchpad = coordinatorScratchpad;
                _currentCoordinatorScratchpad = coordinatorScratchpad; 
            }
            else 
            { 
                coordinatorScratchpad.Depth = _currentCoordinatorScratchpad.Depth + 1;
                _currentCoordinatorScratchpad.AddNestedCoordinator(coordinatorScratchpad); 
                _currentCoordinatorScratchpad = coordinatorScratchpad;
            }
        }
 
        private void ExitCoordinatorTranslateScope()
        { 
            _currentCoordinatorScratchpad = _currentCoordinatorScratchpad.Parent; 
        }
 
        /// 
        /// Return an expression to read the coordinator from a state slot at
        /// runtime.  This is the method where we store the expressions we've
        /// been building into the CoordinatorScratchpad, which we'll compile 
        /// later, once we've left the visitor.
        ///  
        private Expression BuildExpressionToGetCoordinator(Type elementType, Expression element, Expression[] keyReaders, Expression discriminator, object discriminatorValue, CoordinatorScratchpad coordinatorScratchpad) 
        {
            int stateSlotNumber = AllocateStateSlot(); 
            coordinatorScratchpad.StateSlotNumber = stateSlotNumber;

            // Ensure that the element type of the collec element translator
            coordinatorScratchpad.Element = element; 

            // Build expressions to set the key values into their state slots, and 
            // to compare the current values from the source reader with the values 
            // in the slots.
            List setKeyTerms = new List(keyReaders.Length); 
            List checkKeyTerms = new List(keyReaders.Length);

            foreach (Expression keyReader in keyReaders)
            { 
                // allocate space for the key value in the reader state
                int keyStateSlotNumber = AllocateStateSlot(); 
 
                // SetKey: readerState.SetState(stateSlot, keyReader)
                setKeyTerms.Add(Emit_Shaper_SetState(keyStateSlotNumber, keyReader)); 

                // CheckKey: ((T)readerState.State[ordinal]).Equals(keyValue)
                checkKeyTerms.Add(Emit_Equal(
                                        Emit_Shaper_GetState(keyStateSlotNumber, keyReader.Type), 
                                        keyReader
                                        ) 
                                 ); 
            }
 
            // For setting keys, we use BitwiseOr so that we don't short-circuit (all
            // key terms are set)
            coordinatorScratchpad.SetKeys = Emit_BitwiseOr(setKeyTerms);
 
            // When checking for equality, we use AndAlso so that we short-circuit (return
            // as soon as key values don't match) 
            coordinatorScratchpad.CheckKeys = Emit_AndAlso(checkKeyTerms); 

            if (null != discriminator) 
            {
                // discriminatorValue == discriminator
                coordinatorScratchpad.HasData = Emit_Equal(
                                                    Expression.Constant(discriminatorValue, discriminator.Type), 
                                                    discriminator
                                                    ); 
            } 

            // Finally, build the expression to read the coordinator from the state 
            // (Coordinator)readerState.State[stateOrdinal]
            Expression result = Emit_Shaper_GetState(stateSlotNumber, typeof(Coordinator<>).MakeGenericType(elementType));
            return result;
        } 

        #endregion 
 
        #region "scalar" columns
 
        /// 
        /// Visit(RefColumnMap)
        ///
        /// If the entityKey has a value, then return it otherwise return a null 
        /// valued EntityKey.  The EntityKey construction is the tricky part.
        ///  
        internal override TranslatorResult Visit(RefColumnMap columnMap, TranslatorArg arg) 
        {
            EntityIdentity entityIdentity = columnMap.EntityIdentity; 
            Expression entitySetReader; // Ignored here; used when constructing Entities

            // hasValue ? entityKey : (EntityKey)null
            Expression result = Expression.Condition( 
                                                Emit_EntityKey_HasValue(entityIdentity.Keys),
                                                Emit_EntityKey_ctor(this, entityIdentity, true, out entitySetReader), 
                                                Expression.Constant(null, typeof(EntityKey)) 
                                                );
            return new TranslatorResult(result, arg.RequestedType); 
        }

        /// 
        /// Visit(ScalarColumnMap) 
        ///
        /// Pretty basic stuff here; we just call the method that matches the 
        /// type of the column.  Of course we have to handle nullable/non-nullable 
        /// types, and non-value types.
        ///  
        internal override TranslatorResult Visit(ScalarColumnMap columnMap, TranslatorArg arg)
        {
            Type type = arg.RequestedType;
            int ordinal = columnMap.ColumnPos; 
            bool needsNullableCheck;
            MethodInfo readerMethod = GetReaderMethod(type, out needsNullableCheck); 
 
            Expression result = Emit_Reader_GetXXX(ordinal, type, readerMethod);
 
            // if type was Nullable, wrap the expression with check for null
            // value and produce the correct typed null instead.  Strings, of
            // course, can't be Nullable, so we'll always do this.
            if (needsNullableCheck) 
            {
                result = Expression.Condition(Emit_Reader_IsDBNull(ordinal), 
                                              Expression.Constant(TypeSystem.GetDefaultValue(arg.RequestedType), arg.RequestedType), 
                                              result);
            } 

            // also create a version of the expression with error handling so that we can throw
            // better exception messages when needed
            Expression resultWithErrorHandling = Emit_Shaper_GetColumnValueWithErrorHandling(arg.RequestedType, ordinal); 
            _currentCoordinatorScratchpad.AddExpressionWithErrorHandling(result, resultWithErrorHandling);
 
            return new TranslatorResult(result, arg.RequestedType); 
        }
 
        internal static MethodInfo GetReaderMethod(Type type, out bool isNullable)
        {
            Debug.Assert(null != type, "type required");
 
            MethodInfo result;
            isNullable = false; 
 
            // determine if this is a Nullable
            Type underlyingType = Nullable.GetUnderlyingType(type); 
            if (null != underlyingType)
            {
                isNullable = true;
                type = underlyingType; 
            }
 
            TypeCode typeCode = Type.GetTypeCode(type); 

            switch (typeCode) 
            {
                case TypeCode.String:
                    result = DbDataReader_GetString;
                    isNullable = true; 
                    break;
                case TypeCode.Int16: 
                    result = DbDataReader_GetInt16; 
                    break;
                case TypeCode.Int32: 
                    result = DbDataReader_GetInt32;
                    break;
                case TypeCode.Int64:
                    result = DbDataReader_GetInt64; 
                    break;
                case TypeCode.Boolean: 
                    result = DbDataReader_GetBoolean; 
                    break;
                case TypeCode.Decimal: 
                    result = DbDataReader_GetDecimal;
                    break;
                case TypeCode.Double:
                    result = DbDataReader_GetDouble; 
                    break;
                case TypeCode.Single: 
                    result = DbDataReader_GetFloat; 
                    break;
                case TypeCode.DateTime: 
                    result = DbDataReader_GetDateTime;
                    break;
                case TypeCode.Byte:
                    result = DbDataReader_GetByte; 
                    break;
                default: 
                    if (typeof(Guid) == type) 
                    {
                        // Guid doesn't have a type code 
                        result = DbDataReader_GetGuid;
                    }
                    else if (typeof(TimeSpan) == type ||
                             typeof(DateTimeOffset) == type) 
                    {
                        // TimeSpan and DateTimeOffset don't have a type code or a specific 
                        // GetXXX method 
                        result = DbDataReader_GetValue;
                    } 
                    else if (typeof(Object) == type)
                    {
                        // We assume that Object means we want DBNull rather than null. I believe this is a bug.
                        result = DbDataReader_GetValue; 
                    }
                    else 
                    { 
                        result = DbDataReader_GetValue;
                        isNullable = true; 
                    }
                    break;
            }
            return result; 
        }
 
        ///  
        /// Visit(VarRefColumnMap)
        /// 
        /// This should throw; VarRefColumnMaps should be removed by the PlanCompiler.
        /// 
        internal override TranslatorResult Visit(VarRefColumnMap columnMap, TranslatorArg arg)
        { 
            Debug.Fail("VarRefColumnMap should be substituted at this point");
            throw EntityUtil.InvalidOperation(String.Empty); 
        } 

        #endregion 

        #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