private static Func <object, IEntityWrapper> 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 <object, IEntityWrapper>)createDelegate.Invoke(null, new object[0])); }
// See IPropertyAccessorStrategy public void SetNavigationPropertyValue(RelatedEnd relatedEnd, object value) { if (relatedEnd != null) { if (relatedEnd.TargetAccessor.ValueSetter == null) { Type type = GetDeclaringType(relatedEnd); PropertyInfo propertyInfo = EntityUtil.GetTopProperty(ref type, relatedEnd.TargetAccessor.PropertyName); if (propertyInfo == null) { throw new EntityException(System.Data.Entity.Strings.PocoEntityWrapper_UnableToSetFieldOrProperty(relatedEnd.TargetAccessor.PropertyName, type.FullName)); } EntityProxyFactory factory = new EntityProxyFactory(); relatedEnd.TargetAccessor.ValueSetter = factory.CreateBaseSetter(type, propertyInfo); } try { relatedEnd.TargetAccessor.ValueSetter(_entity, value); } catch (Exception ex) { throw new EntityException(System.Data.Entity.Strings.PocoEntityWrapper_UnableToSetFieldOrProperty(relatedEnd.TargetAccessor.PropertyName, _entity.GetType().FullName), ex); } } }
/// <summary> /// 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. /// </summary> /// <param name="entity">The entity for which a wrapper will be created</param> /// <param name="key">The key associated with that entity, or null</param> /// <returns>The new wrapper instance</returns> 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; } // If the entity is a proxy, set the wrapper to match EntityProxyTypeInfo proxyTypeInfo; if (EntityProxyFactory.TryGetProxyType(entity.GetType(), out proxyTypeInfo)) { proxyTypeInfo.SetEntityWrapper(wrappedEntity); } return(wrappedEntity); }
internal static Type GetEntityIdentityType(Type entityType) { if (!EntityProxyFactory.IsProxyType(entityType)) { return(entityType); } return(entityType.BaseType()); }
/// <summary> /// Constructs a wrapper for the given entity. /// Note: use EntityWrapperFactory instead of calling this constructor directly. /// </summary> /// <param name="entity">The entity to wrap</param> internal LightweightEntityWrapper(TEntity entity) : base(entity, entity.RelationshipManager) { Debug.Assert(entity is IEntityWithChangeTracker, "LightweightEntityWrapper only works with entities that implement IEntityWithChangeTracker"); Debug.Assert(entity is IEntityWithRelationships, "LightweightEntityWrapper only works with entities that implement IEntityWithRelationships"); Debug.Assert(entity is IEntityWithKey, "LightweightEntityWrapper only works with entities that implement IEntityWithKey"); Debug.Assert(!EntityProxyFactory.IsProxyType(entity.GetType()), "LightweightEntityWrapper only works with entities that are not proxies"); _entity = entity; }
/// <summary> /// Constructs a wrapper as part of the materialization process. This constructor is only used /// during materialization where it is known that the entity being wrapped is newly constructed. /// This means that some checks are not performed that might be needed when thw wrapper is /// created at other times, and information such as the identity type is passed in because /// it is readily available in the materializer. /// </summary> /// <param name="entity">The entity to wrap</param> /// <param name="key">The key for the entity</param> /// <param name="entitySet">The entity set, or null if none is known</param> /// <param name="context">The context to which the entity should be attached</param> /// <param name="mergeOption">NoTracking for non-tracked entities, AppendOnly otherwise</param> /// <param name="identityType">The type of the entity ignoring any possible proxy type</param> internal LightweightEntityWrapper(TEntity entity, EntityKey key, EntitySet entitySet, ObjectContext context, MergeOption mergeOption, Type identityType) : base(entity, entity.RelationshipManager, entitySet, context, mergeOption, identityType) { Debug.Assert(entity is IEntityWithChangeTracker, "LightweightEntityWrapper only works with entities that implement IEntityWithChangeTracker"); Debug.Assert(entity is IEntityWithRelationships, "LightweightEntityWrapper only works with entities that implement IEntityWithRelationships"); Debug.Assert(entity is IEntityWithKey, "LightweightEntityWrapper only works with entities that implement IEntityWithKey"); Debug.Assert(!EntityProxyFactory.IsProxyType(entity.GetType()), "LightweightEntityWrapper only works with entities that are not proxies"); _entity = entity; _entity.EntityKey = key; }
/// <summary> /// 注册实体代理类型 /// </summary> /// <param name="result"></param> internal static void RegisterCompileResult(List <EntityCompileResult> result) { if (result == null || result.Count == 0) { return; } // 【实体代理类型】允许为空,所以要过滤 List <Type> proxyTypes = (from x in result where x.ProxyType != null select x.ProxyType).ToList(); List <object> loaderInstances = (from x in result select x.LoaderInstnace).ToList(); EntityProxyFactory.BatchRegister(proxyTypes); DataLoaderFactory.BatchRegister(loaderInstances); }
public void Test_EntityProxyFactory_Register() { Product product = Entity.BeginEdit <Product>(); Type t1 = product.GetType(); Assert.AreEqual(typeof(Product), t1.BaseType); // 覆盖初始化时的注册,结果其实是一样的 EntityProxyFactory.Register(t1); Product product2 = Entity.BeginEdit <Product>(); Type t2 = product2.GetType(); Assert.AreEqual(typeof(Product), t2.BaseType); Assert.AreEqual(t1, t2); }
// Creates delegates that create strategy objects appropriate for the type of entity. private static void CreateStrategies <TEntity>(out Func <object, IPropertyAccessorStrategy> createPropertyAccessorStrategy, out Func <object, IChangeTrackingStrategy> createChangeTrackingStrategy, out Func <object, IEntityKeyStrategy> 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(); } }
/// <summary> /// 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. /// </summary> /// <param name="entity">The entity to wrap</param> /// <param name="context">The state manager in which the entity may exist, or null</param> /// <param name="existingEntry">The existing state entry for the given entity if one exists, otherwise null</param> /// <returns>A new or existing wrapper</returns> 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); }
/// <summary> /// Returns the Type object that should be used to identify the type in the o-space /// metadata. This is normally just the type that is passed in, but if the type /// is a proxy that we have generated, then its base type is returned instead. /// This ensures that both proxy entities and normal entities are treated as the /// same kind of entity in the metadata and places where the metadata is used. /// </summary> internal static Type GetEntityIdentityType(Type entityType) { return(EntityProxyFactory.IsProxyType(entityType) ? entityType.BaseType : entityType); }