Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Objects / Internal / EntityWrapper.cs
1 //---------------------------------------------------------------------
2 // <copyright file="EntityWrapper.cs" company="Microsoft">
3 //      Copyright (c) Microsoft Corporation.  All rights reserved.
4 // </copyright>
5 //
6 // @owner       Microsoft
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;
14
15 namespace System.Data.Objects.Internal
16 {
17     /// <summary>
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
20     /// independently.
21     /// </summary>
22     /// <typeparam name="TEntity">The type of entity wrapped</typeparam>
23     internal sealed class EntityWrapperWithoutRelationships<TEntity> : EntityWrapper<TEntity>
24     {
25         /// <summary>
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.
31         /// </summary>
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)
45         {
46         }
47
48         /// <summary>
49         /// Constructs a wrapper for the given entity.
50         /// Note: use EntityWrapperFactory instead of calling this constructor directly.
51         /// </summary>
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)
58         {
59         }
60
61         public override bool OwnsRelationshipManager
62         {
63             get { return false; }
64         }
65
66         public override void TakeSnapshotOfRelationships(EntityEntry entry)
67         {
68             entry.TakeSnapshotOfRelationships();
69         }
70
71         // See IEntityWrapper documentation
72         public override bool RequiresRelationshipChangeTracking
73         {
74             get { return true; }
75         }
76     }
77
78     /// <summary>
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.
81     /// </summary>
82     /// <typeparam name="TEntity">The type of entity wrapped</typeparam>
83     internal sealed class EntityWrapperWithRelationships<TEntity> : EntityWrapper<TEntity>
84         where TEntity : IEntityWithRelationships
85     {
86         /// <summary>
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.
92         /// </summary>
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)
106         {
107         }
108
109         /// <summary>
110         /// Constructs a wrapper for the given entity.
111         /// Note: use EntityWrapperFactory instead of calling this constructor directly.
112         /// </summary>
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)
119         {
120         }
121
122         public override bool OwnsRelationshipManager
123         {
124             get { return true; }
125         }
126
127         public override void TakeSnapshotOfRelationships(EntityEntry entry)
128         {
129         }
130
131         // See IEntityWrapper documentation
132         public override bool RequiresRelationshipChangeTracking
133         {
134             get { return false; }
135         }
136     }
137
138     /// <summary>
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
141     /// are not proxies.
142     /// Different strategies for dealing with these entities are defined by strategy objects that are set into the
143     /// wrapper at constructionn time.
144     /// </summary>
145     internal abstract class EntityWrapper<TEntity> : BaseEntityWrapper<TEntity>
146     {
147         private readonly TEntity _entity;
148         private IPropertyAccessorStrategy _propertyStrategy;
149         private IChangeTrackingStrategy _changeTrackingStrategy;
150         private IEntityKeyStrategy _keyStrategy;
151
152         /// <summary>
153         /// Constructs a wrapper for the given entity.
154         /// Note: use EntityWrapperFactory instead of calling this constructor directly.
155         /// </summary>
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)
164         {
165             if (relationshipManager == null)
166             {
167                 throw EntityUtil.UnexpectedNullRelationshipManager();
168             }
169             _entity = entity;
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.");
175         }
176
177         /// <summary>
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.
183         /// </summary>
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)
197         {
198             if (relationshipManager == null)
199             {
200                 throw EntityUtil.UnexpectedNullRelationshipManager();
201             }
202             _entity = entity;
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);
209         }
210
211         // See IEntityWrapper documentation
212         public override void SetChangeTracker(IEntityChangeTracker changeTracker)
213         {
214             _changeTrackingStrategy.SetChangeTracker(changeTracker);
215         }
216
217         // See IEntityWrapper documentation
218         public override void TakeSnapshot(EntityEntry entry)
219         {
220             _changeTrackingStrategy.TakeSnapshot(entry);
221         }
222
223         // See IEntityWrapper documentation
224         public override EntityKey EntityKey
225         {
226             // If no strategy is set, then the key maintained by the wrapper is used,
227             // otherwise the request is passed to the strategy.
228             get
229             {
230                 return _keyStrategy.GetEntityKey();
231             }
232             set
233             {
234                 _keyStrategy.SetEntityKey(value);
235             }
236         }
237
238         public override EntityKey GetEntityKeyFromEntity()
239         {
240             return _keyStrategy.GetEntityKeyFromEntity();
241         }
242
243         public override void CollectionAdd(RelatedEnd relatedEnd, object value)
244         {
245             if (_propertyStrategy != null)
246             {
247                 _propertyStrategy.CollectionAdd(relatedEnd, value);
248             }
249         }
250
251         public override bool CollectionRemove(RelatedEnd relatedEnd, object value)
252         {
253             return _propertyStrategy != null ? _propertyStrategy.CollectionRemove(relatedEnd, value) : false;
254         }
255
256         // See IEntityWrapper documentation
257         public override void EnsureCollectionNotNull(RelatedEnd relatedEnd)
258         {
259             if (_propertyStrategy != null)
260             {
261                 object collection = _propertyStrategy.GetNavigationPropertyValue(relatedEnd);
262                 if (collection == null)
263                 {
264                     collection = _propertyStrategy.CollectionCreate(relatedEnd);
265                     _propertyStrategy.SetNavigationPropertyValue(relatedEnd, collection);
266                 }
267             }
268         }
269
270         // See IEntityWrapper documentation
271         public override object GetNavigationPropertyValue(RelatedEnd relatedEnd)
272         {
273             return _propertyStrategy != null ? _propertyStrategy.GetNavigationPropertyValue(relatedEnd) : null;
274         }
275
276         // See IEntityWrapper documentation
277         public override void SetNavigationPropertyValue(RelatedEnd relatedEnd, object value)
278         {
279             if (_propertyStrategy != null)
280             {
281                 _propertyStrategy.SetNavigationPropertyValue(relatedEnd, value);
282             }
283         }
284
285         // See IEntityWrapper documentation
286         public override void RemoveNavigationPropertyValue(RelatedEnd relatedEnd, object value)
287         {
288             if (_propertyStrategy != null)
289             {
290                 object currentValue = _propertyStrategy.GetNavigationPropertyValue(relatedEnd);
291
292                 if (Object.ReferenceEquals(currentValue, value))
293                 {
294                     _propertyStrategy.SetNavigationPropertyValue(relatedEnd, null);
295                 }
296             }
297         }
298
299         // See IEntityWrapper documentation
300         public override object Entity
301         {
302             get { return _entity; }
303         }
304
305         // See IEntityWrapper<TEntity> documentation
306         public override TEntity TypedEntity
307         {
308             get { return _entity; }
309         }
310
311         // See IEntityWrapper documentation
312         public override void SetCurrentValue(EntityEntry entry, StateManagerMemberMetadata member, int ordinal, object target, object value)
313         {
314             _changeTrackingStrategy.SetCurrentValue(entry, member, ordinal, target, value);
315         }
316
317         // See IEntityWrapper documentation
318         public override void UpdateCurrentValueRecord(object value, EntityEntry entry)
319         {
320             _changeTrackingStrategy.UpdateCurrentValueRecord(value, entry);
321         }
322     }
323 }