Updates referencesource to .NET 4.7
[mono.git] / mcs / class / referencesource / System.Data.Entity / System / Data / Objects / ObjectStateEntry.cs
1 //---------------------------------------------------------------------
2 // <copyright file="ObjectStateEntry.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.Generic;
10 using System.Data.Common;
11 using System.Data.Metadata.Edm;
12 using System.Data.Objects.DataClasses;
13 using System.Diagnostics;
14 using System.Collections;
15
16 namespace System.Data.Objects
17 {
18     // Detached - nothing
19
20     // Added - _entity & _currentValues only for shadowState
21
22     // Unchanged - _entity & _currentValues only for shadowState
23     // Unchanged -> Deleted - _entity & _currentValues only for shadowState
24
25     // Modified - _currentValues & _modifiedFields + _originalValues only on change
26     // Modified -> Deleted - _currentValues & _modifiedFields + _originalValues only on change
27
28     /// <summary>
29     /// Represets either a entity, entity stub or relationship
30     /// </summary>
31     public abstract class ObjectStateEntry : IEntityStateEntry, IEntityChangeTracker
32     {
33         #region common entry fields
34         internal ObjectStateManager _cache;
35         internal EntitySetBase _entitySet;
36         internal EntityState _state;
37         #endregion
38
39         #region Constructor
40         // ObjectStateEntry will not be detached and creation will be handled from ObjectStateManager
41         internal ObjectStateEntry(ObjectStateManager cache, EntitySet entitySet, EntityState state)
42         {
43             Debug.Assert(cache != null, "cache cannot be null.");
44
45             _cache = cache;
46             _entitySet = entitySet;
47             _state = state;
48         }
49         #endregion // Constructor
50
51         #region Public members
52         /// <summary>
53         /// ObjectStateManager property of ObjectStateEntry.
54         /// </summary>
55         /// <param></param>
56         /// <returns> ObjectStateManager </returns>
57         public ObjectStateManager ObjectStateManager
58         {
59             get
60             {
61                 ValidateState();
62                 return _cache;
63             }
64         }
65
66         /// <summary> Extent property of ObjectStateEntry. </summary>
67         /// <param></param>
68         /// <returns> Extent </returns>
69         public EntitySetBase EntitySet
70         {
71             get
72             {
73                 ValidateState();
74                 return _entitySet;
75             }
76         }
77
78         /// <summary>
79         /// State property of ObjectStateEntry.
80         /// </summary>
81         /// <param></param>
82         /// <returns> DataRowState </returns>
83         public EntityState State
84         {
85             get
86             {
87                 return _state;
88             }
89             internal set
90             {
91                 _state = value;
92             }
93         }
94
95         /// <summary>
96         /// Entity property of ObjectStateEntry.
97         /// </summary>
98         /// <param></param>
99         /// <returns> The entity encapsulated by this entry. </returns>
100         abstract public object Entity { get; }
101
102         /// <summary>
103         /// The EntityKey associated with the ObjectStateEntry
104         /// </summary>
105         abstract public EntityKey EntityKey { get; internal set; }
106
107         /// <summary>
108         /// Determines if this ObjectStateEntry represents a relationship
109         /// </summary>
110         abstract public bool IsRelationship { get; }
111
112         /// <summary>
113         /// Gets bit array indicating which properties are modified.
114         /// </summary>
115         abstract internal BitArray ModifiedProperties { get; }
116
117         BitArray IEntityStateEntry.ModifiedProperties { get { return this.ModifiedProperties; } }
118
119         /// <summary>
120         /// Original values of entity
121         /// </summary>
122         /// <param></param>
123         /// <returns> DbDataRecord </returns>
124         [DebuggerBrowsable(DebuggerBrowsableState.Never)] // don't have debugger view expand this
125         abstract public DbDataRecord OriginalValues { get; }
126
127         abstract public OriginalValueRecord GetUpdatableOriginalValues();
128
129         /// <summary>
130         /// Current values of entity/ DataRow
131         /// </summary>
132         /// <param></param>
133         /// <returns> DbUpdatableDataRecord </returns>
134         [DebuggerBrowsable(DebuggerBrowsableState.Never)] // don't have debugger view expand this
135         abstract public CurrentValueRecord CurrentValues { get; }
136
137         /// <summary>
138         /// API to accept the current values as original values and  mark the entity as Unchanged.
139         /// </summary>
140         /// <param></param>
141         /// <returns></returns>
142         abstract public void AcceptChanges();
143         
144         /// <summary>
145         /// API to mark the entity deleted. if entity is in added state, it will be detached
146         /// </summary>
147         /// <param></param>
148         /// <returns> </returns>
149         abstract public void Delete();
150
151         /// <summary>
152         /// API to return properties that are marked modified
153         /// </summary>
154         /// <param> </param>
155         /// <returns> IEnumerable of modified properties names, names are in term of c-space </returns>
156         abstract public IEnumerable<string> GetModifiedProperties();
157
158         /// <summary>
159         /// set the state to Modified.
160         /// </summary>
161         /// <param></param>
162         /// <returns></returns>
163         /// <exception cref="InvalidOperationException">If State is not Modified or Unchanged</exception>
164         ///
165         abstract public void SetModified();
166
167         /// <summary>
168         /// Marks specified property as modified.
169         /// </summary>
170         /// <param name="propertyName">This API recognizes the names in terms of OSpace</param>
171         /// <exception cref="InvalidOperationException">If State is not Modified or Unchanged</exception>
172         ///
173         abstract public void SetModifiedProperty(string propertyName);
174
175         /// <summary>
176         /// Rejects any changes made to the property with the given name since the property was last loaded,
177         /// attached, saved, or changes were accepted. The orginal value of the property is stored and the
178         /// property will no longer be marked as modified. 
179         /// </summary>
180         /// <remarks>
181         /// If the result is that no properties of the entity are marked as modified, then the entity will
182         /// be marked as Unchanged.
183         /// Changes to properties can only rejected for entities that are in the Modified or Unchanged state.
184         /// Calling this method for entities in other states (Added, Deleted, or Detached) will result in
185         /// an exception being thrown.
186         /// Rejecting changes to properties of an Unchanged entity or unchanged properties of a Modifed
187         /// is a no-op.
188         /// </remarks>
189         /// <param name="propertyName">The name of the property to change.</param>
190         abstract public void RejectPropertyChanges(string propertyName);
191
192         /// <summary>
193         /// Uses DetectChanges to determine whether or not the current value of the property with the given
194         /// name is different from its original value. Note that this may be different from the property being
195         /// marked as modified since a property which has not changed can still be marked as modified.
196         /// </summary>
197         /// <remarks>
198         /// For complex properties, a new instance of the complex object which has all the same property
199         /// values as the original instance is not considered to be different by this method.
200         /// </remarks>
201         /// <param name="propertyName">The name of the property.</param>
202         /// <returns>True if the property has changed; false otherwise.</returns>
203         abstract public bool IsPropertyChanged(string propertyName);
204
205         /// <summary>
206         /// Returns the RelationshipManager for the entity represented by this ObjectStateEntry.
207         /// Note that a RelationshipManager objects can only be returned if this entry represents a
208         /// full entity.  Key-only entries (stubs) and entries representing relationships do not
209         /// have associated RelationshipManagers.
210         /// </summary>
211         /// <exception cref="InvalidOperationException">The entry is a stub or represents a relationship</exception>
212         abstract public RelationshipManager RelationshipManager
213         {
214             get;
215         }
216
217         /// <summary>
218         /// Changes state of the entry to the specified <paramref name="state"/>
219         /// </summary>
220         /// <param name="state">The requested state</param>
221         abstract public void ChangeState(EntityState state);
222
223         /// <summary>
224         /// Apply modified properties to the original object.
225         /// </summary>
226         /// <param name="current">object with modified properties</param>
227         abstract public void ApplyCurrentValues(object currentEntity);
228
229         /// <summary>
230         /// Apply original values to the entity.
231         /// </summary>
232         /// <param name="original">The object with original values</param>
233         abstract public void ApplyOriginalValues(object originalEntity);
234
235         #endregion // Public members
236
237         #region IEntityStateEntry
238         IEntityStateManager IEntityStateEntry.StateManager
239         {
240             get
241             {
242                 return (IEntityStateManager)this.ObjectStateManager;
243             }
244         }
245
246         // must explicitly implement this because interface is internal & so is the property on the
247         // class itself -- apparently the compiler won't let anything marked as internal be part of
248         // an interface (even if the interface is also internal)
249         bool IEntityStateEntry.IsKeyEntry
250         {
251             get
252             {
253                 return this.IsKeyEntry;
254             }
255         }
256         #endregion // IEntityStateEntry
257
258         #region Public IEntityChangeTracker
259
260         /// <summary>
261         /// Used to report that a scalar entity property is about to change
262         /// The current value of the specified property is cached when this method is called.
263         /// </summary>
264         /// <param name="entityMemberName">The name of the entity property that is changing</param>
265         void IEntityChangeTracker.EntityMemberChanging(string entityMemberName)
266         {
267             this.EntityMemberChanging(entityMemberName);
268         }
269
270         /// <summary>
271         /// Used to report that a scalar entity property has been changed
272         /// The property value that was cached during EntityMemberChanging is now
273         /// added to OriginalValues
274         /// </summary>
275         /// <param name="entityMemberName">The name of the entity property that has changing</param>
276         void IEntityChangeTracker.EntityMemberChanged(string entityMemberName)
277         {
278             this.EntityMemberChanged(entityMemberName);
279         }
280
281         /// <summary>
282         /// Used to report that a complex property is about to change
283         /// The current value of the specified property is cached when this method is called.
284         /// </summary>
285         /// <param name="entityMemberName">The name of the top-level entity property that is changing</param>
286         /// <param name="complexObject">The complex object that contains the property that is changing</param>
287         /// <param name="complexObjectMemberName">The name of the property that is changing on complexObject</param>
288         void IEntityChangeTracker.EntityComplexMemberChanging(string entityMemberName, object complexObject, string complexObjectMemberName)
289         {
290             this.EntityComplexMemberChanging(entityMemberName, complexObject, complexObjectMemberName);
291         }
292
293         /// <summary>
294         /// Used to report that a complex property has been changed
295         /// The property value that was cached during EntityMemberChanging is now added to OriginalValues
296         /// </summary>
297         /// <param name="entityMemberName">The name of the top-level entity property that has changed</param>
298         /// <param name="complexObject">The complex object that contains the property that changed</param>
299         /// <param name="complexObjectMemberName">The name of the property that changed on complexObject</param>
300         void IEntityChangeTracker.EntityComplexMemberChanged(string entityMemberName, object complexObject, string complexObjectMemberName)
301         {
302             this.EntityComplexMemberChanged(entityMemberName, complexObject, complexObjectMemberName);
303         }
304
305         /// <summary>
306         /// Returns the EntityState from the ObjectStateEntry
307         /// </summary>
308         EntityState IEntityChangeTracker.EntityState
309         {
310             get
311             {
312                 return this.State;
313             }
314         }
315
316         #endregion // IEntityChangeTracker
317
318         #region Internal members
319
320         abstract internal bool IsKeyEntry { get; }
321
322         abstract internal int GetFieldCount(StateManagerTypeMetadata metadata);
323
324         abstract internal Type GetFieldType(int ordinal, StateManagerTypeMetadata metadata);
325
326         abstract internal string GetCLayerName(int ordinal, StateManagerTypeMetadata metadata);
327
328         abstract internal int GetOrdinalforCLayerName(string name, StateManagerTypeMetadata metadata);
329
330         abstract internal void RevertDelete();
331
332         abstract internal void SetModifiedAll();
333
334         abstract internal void EntityMemberChanging(string entityMemberName);
335         abstract internal void EntityMemberChanged(string entityMemberName);
336         abstract internal void EntityComplexMemberChanging(string entityMemberName, object complexObject, string complexObjectMemberName);
337         abstract internal void EntityComplexMemberChanged(string entityMemberName, object complexObject, string complexObjectMemberName);
338
339         /// <summary>
340         /// Reuse or create a new (Entity)DataRecordInfo.
341         /// </summary>
342         abstract internal DataRecordInfo GetDataRecordInfo(StateManagerTypeMetadata metadata, object userObject);
343
344         virtual internal void Reset()
345         {
346             _cache = null;
347             _entitySet = null;
348             _state = EntityState.Detached;
349         }
350
351         internal void ValidateState()
352         {
353             if (_state == EntityState.Detached)
354             {
355                 throw EntityUtil.ObjectStateEntryinInvalidState();
356             }
357             Debug.Assert(null != _cache, "null ObjectStateManager");
358             Debug.Assert(null != _entitySet, "null EntitySetBase");
359         }
360
361         #endregion // Internal members
362     }
363
364     internal struct StateManagerValue
365     {
366         internal StateManagerMemberMetadata memberMetadata;
367         internal object userObject;
368         internal object originalValue;
369
370         internal StateManagerValue(StateManagerMemberMetadata metadata, object instance, object value)
371         {
372             memberMetadata = metadata;
373             userObject = instance;
374             originalValue = value;
375         }
376     }
377
378     internal enum ObjectStateValueRecord
379     {
380         OriginalReadonly = 0,
381         CurrentUpdatable = 1,
382         OriginalUpdatableInternal = 2,
383         OriginalUpdatablePublic = 3,
384     }
385
386
387     // This class is used in Referential Integrity Constraints feature.
388     // It is used to get around the problem of enumerating dictionary contents, 
389     // but allowing update of the value without breaking the enumerator.
390     internal sealed class IntBox
391     {
392         private int val;
393
394         internal IntBox(int val)
395         {
396             this.val = val;
397         }
398
399         internal int Value 
400         {
401             get
402             {
403                 return val;
404             }
405
406             set 
407             {
408                 val = value;
409             }
410         }
411     }
412 }