EntityWrapperFactory.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / DataEntity / System / Data / Objects / Internal / EntityWrapperFactory.cs / 1599186 / EntityWrapperFactory.cs

                            //---------------------------------------------------------------------- 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// 
// @owner       [....]
// @backupOwner [....] 
//--------------------------------------------------------------------- 
using System.Data.Objects.DataClasses;
using System.Data.Metadata.Edm; 
using System.Diagnostics;
using System.ComponentModel;
using System.Collections.Generic;
using System.Reflection; 
using System.Linq.Expressions;
using System.Security.Permissions; 
using System.Threading; 
using System.Data.Common.Utils;
using System.Runtime.CompilerServices; 

namespace System.Data.Objects.Internal
{
    ///  
    /// Factory class for creating IEntityWrapper instances.
    ///  
    internal static class EntityWrapperFactory 
    {
        // A cache of functions used to create IEntityWrapper instances for a given type 
        private static readonly Memoizer> _delegateCache = new Memoizer>(CreateWrapperDelegate, null);

        /// 
        /// The single instance of the NullEntityWrapper. 
        /// 
        internal static IEntityWrapper NullWrapper 
        { 
            get { return NullEntityWrapper.NullWrapper; }
        } 

        /// 
        /// Called to create a new wrapper outside of the normal materialization process.
        /// This method is typically used when a new entity is created outside the context and then is 
        /// added or attached.  The materializer bypasses this method and calls wrapper constructors
        /// directory for performance reasons. 
        /// This method does not check whether or not the wrapper already exists in the context. 
        /// 
        /// The entity for which a wrapper will be created 
        /// The key associated with that entity, or null
        /// The new wrapper instance
        internal static IEntityWrapper CreateNewWrapper(object entity, EntityKey key)
        { 
            Debug.Assert(!(entity is IEntityWrapper), "Object is an IEntityWrapper instance instead of the raw entity.");
            if (entity == null) 
            { 
                return NullEntityWrapper.NullWrapper;
            } 
            // We used a cache of functions based on the actual type of entity that we need to wrap.
            // Creatung these functions is slow, but once they are created they are relatively fast.
            IEntityWrapper wrappedEntity = _delegateCache.Evaluate(entity.GetType())(entity);
            wrappedEntity.RelationshipManager.SetWrappedOwner(wrappedEntity, entity); 
            // We cast to object here to avoid calling the overridden != operator on EntityKey.
            // This creates a very small perf gain, which is none-the-less significant for lean no-tracking cases. 
            if ((object)key != null && (object)wrappedEntity.EntityKey == null) 
            {
                wrappedEntity.EntityKey = key; 
            }
            return wrappedEntity;
        }
 
        // Creates a delegate that can then be used to create wrappers for a given type.
        // This is slow which is why we only create the delegate once and then cache it. 
        [MethodImpl(MethodImplOptions.NoInlining | MethodImplOptions.NoOptimization)] 
        private static Func CreateWrapperDelegate(Type entityType)
        { 
            // For entities that implement all our interfaces we create a special lightweight wrapper that is both
            // smaller and faster than the strategy-based wrapper.
            // Otherwise, the wrapper is provided with different delegates depending on which interfaces are implemented.
            bool isIEntityWithRelationships = typeof(IEntityWithRelationships).IsAssignableFrom(entityType); 
            bool isIEntityWithChangeTracker = typeof(IEntityWithChangeTracker).IsAssignableFrom(entityType);
            bool isIEntityWithKey = typeof(IEntityWithKey).IsAssignableFrom(entityType); 
            bool isProxy = EntityProxyFactory.IsProxyType(entityType); 
            MethodInfo createDelegate;
            if (isIEntityWithRelationships && isIEntityWithChangeTracker && isIEntityWithKey && !isProxy) 
            {
                createDelegate = typeof(EntityWrapperFactory).GetMethod("CreateWrapperDelegateTypedLightweight", BindingFlags.NonPublic | BindingFlags.Static);
            }
            else if (isIEntityWithRelationships) 
            {
                // This type of strategy wrapper is used when the entity implements IEntityWithRelationships 
                // In this case it is important that the entity itself is used to create the RelationshipManager 
                createDelegate = typeof(EntityWrapperFactory).GetMethod("CreateWrapperDelegateTypedWithRelationships", BindingFlags.NonPublic | BindingFlags.Static);
            } 
            else
            {
                createDelegate = typeof(EntityWrapperFactory).GetMethod("CreateWrapperDelegateTypedWithoutRelationships", BindingFlags.NonPublic | BindingFlags.Static);
            } 
            createDelegate = createDelegate.MakeGenericMethod(entityType);
            return (Func)createDelegate.Invoke(null, new object[0]); 
        } 

        // Returns a delegate that creates the fast LightweightEntityWrapper 
        private static Func CreateWrapperDelegateTypedLightweight()
             where TEntity : IEntityWithRelationships, IEntityWithKey, IEntityWithChangeTracker
        {
            return (entity) => new LightweightEntityWrapper((TEntity)entity); 
        }
 
        // Returns a delegate that creates a strategy-based wrapper for entities that implement IEntityWithRelationships 
        private static Func CreateWrapperDelegateTypedWithRelationships()
            where TEntity : IEntityWithRelationships 
        {
            Func propertyAccessorStrategy;
            Func keyStrategy;
            Func changeTrackingStrategy; 
            CreateStrategies(out propertyAccessorStrategy, out changeTrackingStrategy, out keyStrategy);
 
            return (entity) => new EntityWrapperWithRelationships((TEntity)entity, propertyAccessorStrategy, changeTrackingStrategy, keyStrategy); 
        }
 
        // Returns a delegate that creates a strategy-based wrapper for entities that do not implement IEntityWithRelationships
        private static Func CreateWrapperDelegateTypedWithoutRelationships()
        {
            Func propertyAccessorStrategy; 
            Func keyStrategy;
            Func changeTrackingStrategy; 
            CreateStrategies(out propertyAccessorStrategy, out changeTrackingStrategy, out keyStrategy); 

            return (entity) => new EntityWrapperWithoutRelationships((TEntity)entity, propertyAccessorStrategy, changeTrackingStrategy, keyStrategy); 
        }

        // Creates delegates that create strategy objects appropriate for the type of entity.
        private static void CreateStrategies(out Func createPropertyAccessorStrategy, 
                                                      out Func createChangeTrackingStrategy,
                                                      out Func createKeyStrategy) 
        { 
            Type entityType = typeof(TEntity);
            bool isIEntityWithRelationships = typeof(IEntityWithRelationships).IsAssignableFrom(entityType); 
            bool isIEntityWithChangeTracker = typeof(IEntityWithChangeTracker).IsAssignableFrom(entityType);
            bool isIEntityWithKey = typeof(IEntityWithKey).IsAssignableFrom(entityType);
            bool isProxy = EntityProxyFactory.IsProxyType(entityType);
 
            if (!isIEntityWithRelationships || isProxy)
            { 
                createPropertyAccessorStrategy = GetPocoPropertyAccessorStrategyFunc(); 
            }
            else 
            {
                createPropertyAccessorStrategy = GetNullPropertyAccessorStrategyFunc();
            }
 
            if (isIEntityWithChangeTracker)
            { 
                createChangeTrackingStrategy = GetEntityWithChangeTrackerStrategyFunc(); 
            }
            else 
            {
                createChangeTrackingStrategy = GetSnapshotChangeTrackingStrategyFunc();
            }
 
            if (isIEntityWithKey)
            { 
                createKeyStrategy = GetEntityWithKeyStrategyStrategyFunc(); 
            }
            else 
            {
                createKeyStrategy = GetPocoEntityKeyStrategyFunc();
            }
        } 

        ///  
        /// Convenience function that gets the ObjectStateManager from the context and calls 
        /// WrapEntityUsingStateManager.
        ///  
        /// the entity to wrap
        /// the context in which the entity may exist, or null
        /// a new or existing wrapper
        internal static IEntityWrapper WrapEntityUsingContext(object entity, ObjectContext context) 
        {
            EntityEntry existingEntry; 
            return WrapEntityUsingStateManagerGettingEntry(entity, context == null ? null : context.ObjectStateManager, out existingEntry); 
        }
 
        /// 
        /// Convenience function that gets the ObjectStateManager from the context and calls
        /// WrapEntityUsingStateManager.
        ///  
        /// The entity to wrap
        /// The context in which the entity may exist, or null 
        /// Set to the existing state entry if one is found, else null 
        /// a new or existing wrapper
        internal static IEntityWrapper WrapEntityUsingContextGettingEntry(object entity, ObjectContext context, out EntityEntry existingEntry) 
        {
            return WrapEntityUsingStateManagerGettingEntry(entity, context == null ? null : context.ObjectStateManager, out existingEntry);
        }
 
        /// 
        /// Wraps an entity and returns a new wrapper, or returns an existing wrapper if one 
        /// already exists in the ObjectStateManager or in a RelationshipManager associated with 
        /// the entity.
        ///  
        /// the entity to wrap
        /// the state manager  in which the entity may exist, or null
        /// a new or existing wrapper
        internal static IEntityWrapper WrapEntityUsingStateManager(object entity, ObjectStateManager stateManager) 
        {
            EntityEntry existingEntry; 
            return WrapEntityUsingStateManagerGettingEntry(entity, stateManager, out existingEntry); 
        }
 
        /// 
        /// Wraps an entity and returns a new wrapper, or returns an existing wrapper if one
        /// already exists in the ObjectStateManager or in a RelationshipManager associated with
        /// the entity. 
        /// 
        /// The entity to wrap 
        /// The state manager  in which the entity may exist, or null 
        /// The existing state entry for the given entity if one exists, otherwise null
        /// A new or existing wrapper 
        internal static IEntityWrapper WrapEntityUsingStateManagerGettingEntry(object entity, ObjectStateManager stateManager, out EntityEntry existingEntry)
        {
            Debug.Assert(!(entity is IEntityWrapper), "Object is an IEntityWrapper instance instead of the raw entity.");
            IEntityWrapper wrapper = null; 
            existingEntry = null;
 
            if (entity == null) 
            {
                return NullEntityWrapper.NullWrapper; 
            }
            // First attempt to find an existing wrapper in the ObjectStateMager.
            if (stateManager != null)
            { 
                existingEntry = stateManager.FindEntityEntry(entity);
                if (existingEntry != null) 
                { 
                    return existingEntry.WrappedEntity;
                } 
                if (stateManager.TransactionManager.TrackProcessedEntities)
                {
                    if (stateManager.TransactionManager.WrappedEntities.TryGetValue(entity, out wrapper))
                    { 
                        return wrapper;
                    } 
                } 
            }
            // If no entity was found in the OSM, then check if one exists on an associated 
            // RelationshipManager.  This only works where the entity implements IEntityWithRelationshops.
            IEntityWithRelationships entityWithRelationships = entity as IEntityWithRelationships;
            if (entityWithRelationships != null)
            { 
                RelationshipManager relManager = entityWithRelationships.RelationshipManager;
                if (relManager == null) 
                { 
                    throw EntityUtil.UnexpectedNullRelationshipManager();
                } 
                IEntityWrapper wrappedEntity = relManager.WrappedOwner;
                if (!Object.ReferenceEquals(wrappedEntity.Entity, entity))
                {
                    // This means that the owner of the RelationshipManager must have been set 
                    // incorrectly in the call to RelationshipManager.Create().
                    throw EntityUtil.InvalidRelationshipManagerOwner(); 
                } 
                return wrappedEntity;
            } 
            else
            {
                // Finally look to see if the instance is a proxy and get the wrapper from the proxy
                EntityProxyFactory.TryGetProxyWrapper(entity, out wrapper); 
            }
 
            // If we could not find an existing wrapper, then go create a new one 
            if (wrapper == null)
            { 
                IEntityWithKey withKey = entity as IEntityWithKey;
                wrapper = CreateNewWrapper(entity, withKey == null ? null : withKey.EntityKey);
            }
            if (stateManager != null && stateManager.TransactionManager.TrackProcessedEntities) 
            {
                stateManager.TransactionManager.WrappedEntities.Add(entity, wrapper); 
            } 
            return wrapper;
        } 

        /// 
        /// When an entity enters Object Services that was retreived with NoTracking, it may not have certain fields set that are in many cases
        /// assumed to be present. This method updates the wrapper with a key and a context. 
        /// 
        /// The wrapped entity 
        /// The context that will be using this wrapper 
        /// The entity set this wrapped entity belongs to
        internal static void UpdateNoTrackingWrapper(IEntityWrapper wrapper, ObjectContext context, EntitySet entitySet) 
        {
            if (wrapper.EntityKey == null)
            {
                wrapper.EntityKey = context.ObjectStateManager.CreateEntityKey(entitySet, wrapper.Entity); 
            }
            if (wrapper.Context == null) 
            { 
                wrapper.AttachContext(context, entitySet, MergeOption.NoTracking);
            } 
        }

        /// 
        /// Returns a func that will create a PocoPropertyAccessorStrategy object for a given entity. 
        /// 
        /// The func to be used to create the strategy object. 
        internal static Func GetPocoPropertyAccessorStrategyFunc() 
        {
            return (object entity) => new PocoPropertyAccessorStrategy(entity); 
        }

        /// 
        /// Returns a func that will create a null IPropertyAccessorStrategy strategy object for a given entity. 
        /// 
        /// The func to be used to create the strategy object. 
        internal static Func GetNullPropertyAccessorStrategyFunc() 
        {
            return (object entity) => null; 
        }

        /// 
        /// Returns a func that will create a EntityWithChangeTrackerStrategy object for a given entity. 
        /// 
        /// The func to be used to create the strategy object. 
        internal static Func GetEntityWithChangeTrackerStrategyFunc() 
        {
            return (object entity) => new EntityWithChangeTrackerStrategy((IEntityWithChangeTracker)entity); 
        }

        /// 
        /// Returns a func that will create a SnapshotChangeTrackingStrategy object for a given entity. 
        /// 
        /// The func to be used to create the strategy object. 
        internal static Func GetSnapshotChangeTrackingStrategyFunc() 
        {
            return (object entity) => SnapshotChangeTrackingStrategy.Instance; 
        }

        /// 
        /// Returns a func that will create a EntityWithKeyStrategy object for a given entity. 
        /// 
        /// The func to be used to create the strategy object. 
        internal static Func GetEntityWithKeyStrategyStrategyFunc() 
        {
            return (object entity) => new EntityWithKeyStrategy((IEntityWithKey)entity); 
        }

        /// 
        /// Returns a func that will create a GetPocoEntityKeyStrategyFunc object for a given entity. 
        /// 
        /// The func to be used to create the strategy object. 
        internal static Func GetPocoEntityKeyStrategyFunc() 
        {
            return (object entity) => new PocoEntityKeyStrategy(); 
        }
    }
}

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