1 //---------------------------------------------------------------------
2 // <copyright file="EntityWrapper.cs" company="Microsoft">
3 // Copyright (c) Microsoft Corporation. All rights reserved.
7 // @backupOwner Microsoft
8 //---------------------------------------------------------------------
9 using System.Collections;
10 using System.Data.Objects.DataClasses;
11 using System.Diagnostics;
12 using System.Reflection;
13 using System.Data.Metadata.Edm;
15 namespace System.Data.Objects.Internal
18 /// An extension of the EntityWrapper class for entities that are known not to implement
19 /// IEntityWithRelationships. Using this class causes the RelationshipManager to be created
22 /// <typeparam name="TEntity">The type of entity wrapped</typeparam>
23 internal sealed class EntityWrapperWithoutRelationships<TEntity> : EntityWrapper<TEntity>
26 /// Constructs a wrapper as part of the materialization process. This constructor is only used
27 /// during materialization where it is known that the entity being wrapped is newly constructed.
28 /// This means that some checks are not performed that might be needed when thw wrapper is
29 /// created at other times, and information such as the identity type is passed in because
30 /// it is readily available in the materializer.
32 /// <param name="entity">The entity to wrap</param>
33 /// <param name="key">The entity's key</param>
34 /// <param name="entitySet">The entity set, or null if none is known</param>
35 /// <param name="context">The context to which the entity should be attached</param>
36 /// <param name="mergeOption">NoTracking for non-tracked entities, AppendOnly otherwise</param>
37 /// <param name="identityType">The type of the entity ignoring any possible proxy type</param>
38 /// <param name="propertyStrategy">A delegate to create the property accesor strategy object</param>
39 /// <param name="changeTrackingStrategy">A delegate to create the change tracking strategy object</param>
40 /// <param name="keyStrategy">A delegate to create the entity key strategy object</param>
41 internal EntityWrapperWithoutRelationships(TEntity entity, EntityKey key, EntitySet entitySet, ObjectContext context, MergeOption mergeOption, Type identityType,
42 Func<object, IPropertyAccessorStrategy> propertyStrategy, Func<object, IChangeTrackingStrategy> changeTrackingStrategy, Func<object, IEntityKeyStrategy> keyStrategy)
43 : base(entity, RelationshipManager.Create(), key, entitySet, context, mergeOption, identityType,
44 propertyStrategy, changeTrackingStrategy, keyStrategy)
49 /// Constructs a wrapper for the given entity.
50 /// Note: use EntityWrapperFactory instead of calling this constructor directly.
52 /// <param name="entity">The entity to wrap</param>
53 /// <param name="propertyStrategy">A delegate to create the property accesor strategy object</param>
54 /// <param name="changeTrackingStrategy">A delegate to create the change tracking strategy object</param>
55 /// <param name="keyStrategy">A delegate to create the entity key strategy object</param>
56 internal EntityWrapperWithoutRelationships(TEntity entity, Func<object, IPropertyAccessorStrategy> propertyStrategy, Func<object, IChangeTrackingStrategy> changeTrackingStrategy, Func<object, IEntityKeyStrategy> keyStrategy)
57 : base(entity, RelationshipManager.Create(), propertyStrategy, changeTrackingStrategy, keyStrategy)
61 public override bool OwnsRelationshipManager
66 public override void TakeSnapshotOfRelationships(EntityEntry entry)
68 entry.TakeSnapshotOfRelationships();
71 // See IEntityWrapper documentation
72 public override bool RequiresRelationshipChangeTracking
79 /// An extension of the EntityWrapper class for entities that implement IEntityWithRelationships.
80 /// Using this class causes creation of the RelationshipManager to be defered to the entity object.
82 /// <typeparam name="TEntity">The type of entity wrapped</typeparam>
83 internal sealed class EntityWrapperWithRelationships<TEntity> : EntityWrapper<TEntity>
84 where TEntity : IEntityWithRelationships
87 /// Constructs a wrapper as part of the materialization process. This constructor is only used
88 /// during materialization where it is known that the entity being wrapped is newly constructed.
89 /// This means that some checks are not performed that might be needed when thw wrapper is
90 /// created at other times, and information such as the identity type is passed in because
91 /// it is readily available in the materializer.
93 /// <param name="entity">The entity to wrap</param>
94 /// <param name="key">The entity's key</param>
95 /// <param name="entitySet">The entity set, or null if none is known</param>
96 /// <param name="context">The context to which the entity should be attached</param>
97 /// <param name="mergeOption">NoTracking for non-tracked entities, AppendOnly otherwise</param>
98 /// <param name="identityType">The type of the entity ignoring any possible proxy type</param>
99 /// <param name="propertyStrategy">A delegate to create the property accesor strategy object</param>
100 /// <param name="changeTrackingStrategy">A delegate to create the change tracking strategy object</param>
101 /// <param name="keyStrategy">A delegate to create the entity key strategy object</param>
102 internal EntityWrapperWithRelationships(TEntity entity, EntityKey key, EntitySet entitySet, ObjectContext context, MergeOption mergeOption, Type identityType,
103 Func<object, IPropertyAccessorStrategy> propertyStrategy, Func<object, IChangeTrackingStrategy> changeTrackingStrategy, Func<object, IEntityKeyStrategy> keyStrategy)
104 : base(entity, entity.RelationshipManager, key, entitySet, context, mergeOption, identityType,
105 propertyStrategy, changeTrackingStrategy, keyStrategy)
110 /// Constructs a wrapper for the given entity.
111 /// Note: use EntityWrapperFactory instead of calling this constructor directly.
113 /// <param name="entity">The entity to wrap</param>
114 /// <param name="propertyStrategy">A delegate to create the property accesor strategy object</param>
115 /// <param name="changeTrackingStrategy">A delegate to create the change tracking strategy object</param>
116 /// <param name="keyStrategy">A delegate to create the entity key strategy object</param>
117 internal EntityWrapperWithRelationships(TEntity entity, Func<object, IPropertyAccessorStrategy> propertyStrategy, Func<object, IChangeTrackingStrategy> changeTrackingStrategy, Func<object, IEntityKeyStrategy> keyStrategy)
118 : base(entity, entity.RelationshipManager, propertyStrategy, changeTrackingStrategy, keyStrategy)
122 public override bool OwnsRelationshipManager
127 public override void TakeSnapshotOfRelationships(EntityEntry entry)
131 // See IEntityWrapper documentation
132 public override bool RequiresRelationshipChangeTracking
134 get { return false; }
139 /// Implementation of the IEntityWrapper interface that is used for non-null entities that do not implement
140 /// all of our standard interfaces: IEntityWithKey, IEntityWithRelationships, and IEntityWithChangeTracker, and
142 /// Different strategies for dealing with these entities are defined by strategy objects that are set into the
143 /// wrapper at constructionn time.
145 internal abstract class EntityWrapper<TEntity> : BaseEntityWrapper<TEntity>
147 private readonly TEntity _entity;
148 private IPropertyAccessorStrategy _propertyStrategy;
149 private IChangeTrackingStrategy _changeTrackingStrategy;
150 private IEntityKeyStrategy _keyStrategy;
153 /// Constructs a wrapper for the given entity.
154 /// Note: use EntityWrapperFactory instead of calling this constructor directly.
156 /// <param name="entity">The entity to wrap</param>
157 /// <param name="relationshipManager">The RelationshipManager associated with the entity</param>
158 /// <param name="propertyStrategy">A delegate to create the property accesor strategy object</param>
159 /// <param name="changeTrackingStrategy">A delegate to create the change tracking strategy object</param>
160 /// <param name="keyStrategy">A delegate to create the entity key strategy object</param>
161 protected EntityWrapper(TEntity entity, RelationshipManager relationshipManager,
162 Func<object, IPropertyAccessorStrategy> propertyStrategy, Func<object, IChangeTrackingStrategy> changeTrackingStrategy, Func<object, IEntityKeyStrategy> keyStrategy)
163 : base(entity, relationshipManager)
165 if (relationshipManager == null)
167 throw EntityUtil.UnexpectedNullRelationshipManager();
170 _propertyStrategy = propertyStrategy(entity);
171 _changeTrackingStrategy = changeTrackingStrategy(entity);
172 _keyStrategy = keyStrategy(entity);
173 Debug.Assert(_changeTrackingStrategy != null, "Change tracking strategy cannot be null.");
174 Debug.Assert(_keyStrategy != null, "Key strategy cannot be null.");
178 /// Constructs a wrapper as part of the materialization process. This constructor is only used
179 /// during materialization where it is known that the entity being wrapped is newly constructed.
180 /// This means that some checks are not performed that might be needed when thw wrapper is
181 /// created at other times, and information such as the identity type is passed in because
182 /// it is readily available in the materializer.
184 /// <param name="entity">The entity to wrap</param>
185 /// <param name="relationshipManager">The RelationshipManager associated with the entity</param>
186 /// <param name="key">The entity's key</param>
187 /// <param name="entitySet">The entity set, or null if none is known</param>
188 /// <param name="context">The context to which the entity should be attached</param>
189 /// <param name="mergeOption">NoTracking for non-tracked entities, AppendOnly otherwise</param>
190 /// <param name="identityType">The type of the entity ignoring any possible proxy type</param>
191 /// <param name="propertyStrategy">A delegate to create the property accesor strategy object</param>
192 /// <param name="changeTrackingStrategy">A delegate to create the change tracking strategy object</param>
193 /// <param name="keyStrategy">A delegate to create the entity key strategy object</param>
194 protected EntityWrapper(TEntity entity, RelationshipManager relationshipManager, EntityKey key, EntitySet set, ObjectContext context, MergeOption mergeOption, Type identityType,
195 Func<object, IPropertyAccessorStrategy> propertyStrategy, Func<object, IChangeTrackingStrategy> changeTrackingStrategy, Func<object, IEntityKeyStrategy> keyStrategy)
196 : base(entity, relationshipManager, set, context, mergeOption, identityType)
198 if (relationshipManager == null)
200 throw EntityUtil.UnexpectedNullRelationshipManager();
203 _propertyStrategy = propertyStrategy(entity);
204 _changeTrackingStrategy = changeTrackingStrategy(entity);
205 _keyStrategy = keyStrategy(entity);
206 Debug.Assert(_changeTrackingStrategy != null, "Change tracking strategy cannot be null.");
207 Debug.Assert(_keyStrategy != null, "Key strategy cannot be null.");
208 _keyStrategy.SetEntityKey(key);
211 // See IEntityWrapper documentation
212 public override void SetChangeTracker(IEntityChangeTracker changeTracker)
214 _changeTrackingStrategy.SetChangeTracker(changeTracker);
217 // See IEntityWrapper documentation
218 public override void TakeSnapshot(EntityEntry entry)
220 _changeTrackingStrategy.TakeSnapshot(entry);
223 // See IEntityWrapper documentation
224 public override EntityKey EntityKey
226 // If no strategy is set, then the key maintained by the wrapper is used,
227 // otherwise the request is passed to the strategy.
230 return _keyStrategy.GetEntityKey();
234 _keyStrategy.SetEntityKey(value);
238 public override EntityKey GetEntityKeyFromEntity()
240 return _keyStrategy.GetEntityKeyFromEntity();
243 public override void CollectionAdd(RelatedEnd relatedEnd, object value)
245 if (_propertyStrategy != null)
247 _propertyStrategy.CollectionAdd(relatedEnd, value);
251 public override bool CollectionRemove(RelatedEnd relatedEnd, object value)
253 return _propertyStrategy != null ? _propertyStrategy.CollectionRemove(relatedEnd, value) : false;
256 // See IEntityWrapper documentation
257 public override void EnsureCollectionNotNull(RelatedEnd relatedEnd)
259 if (_propertyStrategy != null)
261 object collection = _propertyStrategy.GetNavigationPropertyValue(relatedEnd);
262 if (collection == null)
264 collection = _propertyStrategy.CollectionCreate(relatedEnd);
265 _propertyStrategy.SetNavigationPropertyValue(relatedEnd, collection);
270 // See IEntityWrapper documentation
271 public override object GetNavigationPropertyValue(RelatedEnd relatedEnd)
273 return _propertyStrategy != null ? _propertyStrategy.GetNavigationPropertyValue(relatedEnd) : null;
276 // See IEntityWrapper documentation
277 public override void SetNavigationPropertyValue(RelatedEnd relatedEnd, object value)
279 if (_propertyStrategy != null)
281 _propertyStrategy.SetNavigationPropertyValue(relatedEnd, value);
285 // See IEntityWrapper documentation
286 public override void RemoveNavigationPropertyValue(RelatedEnd relatedEnd, object value)
288 if (_propertyStrategy != null)
290 object currentValue = _propertyStrategy.GetNavigationPropertyValue(relatedEnd);
292 if (Object.ReferenceEquals(currentValue, value))
294 _propertyStrategy.SetNavigationPropertyValue(relatedEnd, null);
299 // See IEntityWrapper documentation
300 public override object Entity
302 get { return _entity; }
305 // See IEntityWrapper<TEntity> documentation
306 public override TEntity TypedEntity
308 get { return _entity; }
311 // See IEntityWrapper documentation
312 public override void SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, int ordinal, object target, object value)
314 _changeTrackingStrategy.SetCurrentValue(entry, member, ordinal, target, value);
317 // See IEntityWrapper documentation
318 public override void UpdateCurrentValueRecord(object value, EntityEntry entry)
320 _changeTrackingStrategy.UpdateCurrentValueRecord(value, entry);