//--------------------------------------------------------------------- // // Copyright (c) Microsoft Corporation. All rights reserved. // // // @owner [....] // @backupOwner [....] //--------------------------------------------------------------------- using System.Collections; using System.Data.Objects.DataClasses; using System.Diagnostics; using System.Reflection; using System.Data.Metadata.Edm; namespace System.Data.Objects.Internal { /// /// An extension of the EntityWrapper class for entities that are known not to implement /// IEntityWithRelationships. Using this class causes the RelationshipManager to be created /// independently. /// /// The type of entity wrapped internal sealed class EntityWrapperWithoutRelationships : EntityWrapper { /// /// 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. /// /// The entity to wrap /// The entity's key /// The entity set, or null if none is known /// The context to which the entity should be attached /// NoTracking for non-tracked entities, AppendOnly otherwise /// The type of the entity ignoring any possible proxy type /// A delegate to create the property accesor strategy object /// A delegate to create the change tracking strategy object /// A delegate to create the entity key strategy object internal EntityWrapperWithoutRelationships(TEntity entity, EntityKey key, EntitySet entitySet, ObjectContext context, MergeOption mergeOption, Type identityType, Func propertyStrategy, Func changeTrackingStrategy, Func keyStrategy) : base(entity, RelationshipManager.Create(), key, entitySet, context, mergeOption, identityType, propertyStrategy, changeTrackingStrategy, keyStrategy) { } /// /// Constructs a wrapper for the given entity. /// Note: use EntityWrapperFactory instead of calling this constructor directly. /// /// The entity to wrap /// A delegate to create the property accesor strategy object /// A delegate to create the change tracking strategy object /// A delegate to create the entity key strategy object internal EntityWrapperWithoutRelationships(TEntity entity, Func propertyStrategy, Func changeTrackingStrategy, Func keyStrategy) : base(entity, RelationshipManager.Create(), propertyStrategy, changeTrackingStrategy, keyStrategy) { } public override bool OwnsRelationshipManager { get { return false; } } public override void TakeSnapshotOfRelationships(EntityEntry entry) { entry.TakeSnapshotOfRelationships(); } // See IEntityWrapper documentation public override bool RequiresRelationshipChangeTracking { get { return true; } } } /// /// An extension of the EntityWrapper class for entities that implement IEntityWithRelationships. /// Using this class causes creation of the RelationshipManager to be defered to the entity object. /// /// The type of entity wrapped internal sealed class EntityWrapperWithRelationships : EntityWrapper where TEntity : IEntityWithRelationships { /// /// 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. /// /// The entity to wrap /// The entity's key /// The entity set, or null if none is known /// The context to which the entity should be attached /// NoTracking for non-tracked entities, AppendOnly otherwise /// The type of the entity ignoring any possible proxy type /// A delegate to create the property accesor strategy object /// A delegate to create the change tracking strategy object /// A delegate to create the entity key strategy object internal EntityWrapperWithRelationships(TEntity entity, EntityKey key, EntitySet entitySet, ObjectContext context, MergeOption mergeOption, Type identityType, Func propertyStrategy, Func changeTrackingStrategy, Func keyStrategy) : base(entity, entity.RelationshipManager, key, entitySet, context, mergeOption, identityType, propertyStrategy, changeTrackingStrategy, keyStrategy) { } /// /// Constructs a wrapper for the given entity. /// Note: use EntityWrapperFactory instead of calling this constructor directly. /// /// The entity to wrap /// A delegate to create the property accesor strategy object /// A delegate to create the change tracking strategy object /// A delegate to create the entity key strategy object internal EntityWrapperWithRelationships(TEntity entity, Func propertyStrategy, Func changeTrackingStrategy, Func keyStrategy) : base(entity, entity.RelationshipManager, propertyStrategy, changeTrackingStrategy, keyStrategy) { } public override bool OwnsRelationshipManager { get { return true; } } public override void TakeSnapshotOfRelationships(EntityEntry entry) { } // See IEntityWrapper documentation public override bool RequiresRelationshipChangeTracking { get { return false; } } } /// /// Implementation of the IEntityWrapper interface that is used for non-null entities that do not implement /// all of our standard interfaces: IEntityWithKey, IEntityWithRelationships, and IEntityWithChangeTracker, and /// are not proxies. /// Different strategies for dealing with these entities are defined by strategy objects that are set into the /// wrapper at constructionn time. /// internal abstract class EntityWrapper : BaseEntityWrapper { private readonly TEntity _entity; private IPropertyAccessorStrategy _propertyStrategy; private IChangeTrackingStrategy _changeTrackingStrategy; private IEntityKeyStrategy _keyStrategy; /// /// Constructs a wrapper for the given entity. /// Note: use EntityWrapperFactory instead of calling this constructor directly. /// /// The entity to wrap /// The RelationshipManager associated with the entity /// A delegate to create the property accesor strategy object /// A delegate to create the change tracking strategy object /// A delegate to create the entity key strategy object protected EntityWrapper(TEntity entity, RelationshipManager relationshipManager, Func propertyStrategy, Func changeTrackingStrategy, Func keyStrategy) : base(entity, relationshipManager) { if (relationshipManager == null) { throw EntityUtil.UnexpectedNullRelationshipManager(); } _entity = entity; _propertyStrategy = propertyStrategy(entity); _changeTrackingStrategy = changeTrackingStrategy(entity); _keyStrategy = keyStrategy(entity); Debug.Assert(_changeTrackingStrategy != null, "Change tracking strategy cannot be null."); Debug.Assert(_keyStrategy != null, "Key strategy cannot be null."); } /// /// 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. /// /// The entity to wrap /// The RelationshipManager associated with the entity /// The entity's key /// The entity set, or null if none is known /// The context to which the entity should be attached /// NoTracking for non-tracked entities, AppendOnly otherwise /// The type of the entity ignoring any possible proxy type /// A delegate to create the property accesor strategy object /// A delegate to create the change tracking strategy object /// A delegate to create the entity key strategy object protected EntityWrapper(TEntity entity, RelationshipManager relationshipManager, EntityKey key, EntitySet set, ObjectContext context, MergeOption mergeOption, Type identityType, Func propertyStrategy, Func changeTrackingStrategy, Func keyStrategy) : base(entity, relationshipManager, set, context, mergeOption, identityType) { if (relationshipManager == null) { throw EntityUtil.UnexpectedNullRelationshipManager(); } _entity = entity; _propertyStrategy = propertyStrategy(entity); _changeTrackingStrategy = changeTrackingStrategy(entity); _keyStrategy = keyStrategy(entity); Debug.Assert(_changeTrackingStrategy != null, "Change tracking strategy cannot be null."); Debug.Assert(_keyStrategy != null, "Key strategy cannot be null."); _keyStrategy.SetEntityKey(key); } // See IEntityWrapper documentation public override void SetChangeTracker(IEntityChangeTracker changeTracker) { _changeTrackingStrategy.SetChangeTracker(changeTracker); } // See IEntityWrapper documentation public override void TakeSnapshot(EntityEntry entry) { _changeTrackingStrategy.TakeSnapshot(entry); } // See IEntityWrapper documentation public override EntityKey EntityKey { // If no strategy is set, then the key maintained by the wrapper is used, // otherwise the request is passed to the strategy. get { return _keyStrategy.GetEntityKey(); } set { _keyStrategy.SetEntityKey(value); } } public override EntityKey GetEntityKeyFromEntity() { return _keyStrategy.GetEntityKeyFromEntity(); } public override void CollectionAdd(RelatedEnd relatedEnd, object value) { if (_propertyStrategy != null) { _propertyStrategy.CollectionAdd(relatedEnd, value); } } public override bool CollectionRemove(RelatedEnd relatedEnd, object value) { return _propertyStrategy != null ? _propertyStrategy.CollectionRemove(relatedEnd, value) : false; } // See IEntityWrapper documentation public override void EnsureCollectionNotNull(RelatedEnd relatedEnd) { if (_propertyStrategy != null) { object collection = _propertyStrategy.GetNavigationPropertyValue(relatedEnd); if (collection == null) { collection = _propertyStrategy.CollectionCreate(relatedEnd); _propertyStrategy.SetNavigationPropertyValue(relatedEnd, collection); } } } // See IEntityWrapper documentation public override object GetNavigationPropertyValue(RelatedEnd relatedEnd) { return _propertyStrategy != null ? _propertyStrategy.GetNavigationPropertyValue(relatedEnd) : null; } // See IEntityWrapper documentation public override void SetNavigationPropertyValue(RelatedEnd relatedEnd, object value) { if (_propertyStrategy != null) { _propertyStrategy.SetNavigationPropertyValue(relatedEnd, value); } } // See IEntityWrapper documentation public override void RemoveNavigationPropertyValue(RelatedEnd relatedEnd, object value) { if (_propertyStrategy != null) { object currentValue = _propertyStrategy.GetNavigationPropertyValue(relatedEnd); if (Object.ReferenceEquals(currentValue, value)) { _propertyStrategy.SetNavigationPropertyValue(relatedEnd, null); } } } // See IEntityWrapper documentation public override object Entity { get { return _entity; } } // See IEntityWrapper documentation public override TEntity TypedEntity { get { return _entity; } } // See IEntityWrapper documentation public override void SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, int ordinal, object target, object value) { _changeTrackingStrategy.SetCurrentValue(entry, member, ordinal, target, value); } // See IEntityWrapper documentation public override void UpdateCurrentValueRecord(object value, EntityEntry entry) { _changeTrackingStrategy.UpdateCurrentValueRecord(value, entry); } } }