88using System ;
99using System . Collections . Concurrent ;
1010using System . Collections . Generic ;
11- using System . Diagnostics ;
1211using System . Diagnostics . CodeAnalysis ;
1312using System . Diagnostics . Contracts ;
1413using System . Linq ;
1514using System . Reflection ;
1615using System . Runtime . CompilerServices ;
17- using Microsoft . AspNet . OData . Builder . Conventions . Attributes ;
1816using Microsoft . AspNet . OData . Common ;
1917using Microsoft . AspNet . OData . Formatter ;
2018
@@ -28,11 +26,11 @@ namespace Microsoft.AspNet.OData
2826 public class Delta < TStructuralType > : TypedDelta , IDelta where TStructuralType : class
2927 {
3028 // cache property accessors for this type and all its derived types.
31- private static ConcurrentDictionary < Type , Dictionary < string , PropertyAccessor < TStructuralType > > > _propertyCache
29+ private static readonly ConcurrentDictionary < Type , Dictionary < string , PropertyAccessor < TStructuralType > > > _propertyCache
3230 = new ConcurrentDictionary < Type , Dictionary < string , PropertyAccessor < TStructuralType > > > ( ) ;
3331
3432 private Dictionary < string , PropertyAccessor < TStructuralType > > _allProperties ;
35- private HashSet < string > _updatableProperties ;
33+ private List < string > _updatableProperties ;
3634
3735 private HashSet < string > _changedProperties ;
3836
@@ -42,7 +40,7 @@ private static ConcurrentDictionary<Type, Dictionary<string, PropertyAccessor<TS
4240 private TStructuralType _instance ;
4341 private Type _structuredType ;
4442
45- private PropertyInfo _dynamicDictionaryPropertyinfo ;
43+ private readonly PropertyInfo _dynamicDictionaryPropertyinfo ;
4644 private HashSet < string > _changedDynamicProperties ;
4745 private IDictionary < string , object > _dynamicDictionaryCache ;
4846
@@ -98,18 +96,19 @@ public Delta(Type structuralType, IEnumerable<string> updatableProperties,
9896
9997 /// <inheritdoc/>
10098 public override Type StructuredType
101- {
102- get
103- {
104- return _structuredType ;
105- }
106- }
99+ => _structuredType ;
107100
108101 /// <inheritdoc/>
109102 public override Type ExpectedClrType
110- {
111- get { return typeof ( TStructuralType ) ; }
112- }
103+ => typeof ( TStructuralType ) ;
104+
105+ /// <summary>
106+ /// The list of property names that can be updated.
107+ /// </summary>
108+ /// <remarks>When the list is modified, any modified properties that were removed from the list are no longer
109+ /// considered to be changed.</remarks>
110+ public IList < string > UpdatableProperties
111+ => _updatableProperties ;
113112
114113 /// <inheritdoc/>
115114 public override void Clear ( )
@@ -120,7 +119,7 @@ public override void Clear()
120119 /// <inheritdoc/>
121120 public override bool TrySetPropertyValue ( string name , object value )
122121 {
123- if ( string . IsNullOrWhiteSpace ( name ) )
122+ if ( String . IsNullOrWhiteSpace ( name ) )
124123 {
125124 throw Error . ArgumentNull ( "name" ) ;
126125 }
@@ -175,7 +174,7 @@ public override bool TryGetPropertyValue(string name, out object value)
175174 }
176175 }
177176
178- if ( this . _deltaNestedResources . ContainsKey ( name ) )
177+ if ( _deltaNestedResources . ContainsKey ( name ) )
179178 {
180179 // If this is a nested resource, get the value from the dictionary of nested resources.
181180 object deltaNestedResource = _deltaNestedResources [ name ] ;
@@ -263,7 +262,7 @@ public TStructuralType GetInstance()
263262 /// </summary>
264263 public override IEnumerable < string > GetChangedPropertyNames ( )
265264 {
266- return _changedProperties . Concat ( _deltaNestedResources . Keys ) ;
265+ return _changedProperties . Intersect ( _updatableProperties ) . Concat ( _deltaNestedResources . Keys ) ;
267266 }
268267
269268 /// <summary>
@@ -273,7 +272,8 @@ public override IEnumerable<string> GetChangedPropertyNames()
273272 /// </summary>
274273 public override IEnumerable < string > GetUnchangedPropertyNames ( )
275274 {
276- return _updatableProperties . Except ( GetChangedPropertyNames ( ) ) ;
275+ // UpdatableProperties could include arbitrary strings, filter by _allProperties
276+ return _updatableProperties . Intersect ( _allProperties . Keys ) . Except ( GetChangedPropertyNames ( ) ) ;
277277 }
278278
279279 /// <summary>
@@ -299,7 +299,7 @@ public void CopyChangedValues(TStructuralType original)
299299
300300 // For regular non-structural properties at current level.
301301 PropertyAccessor < TStructuralType > [ ] propertiesToCopy =
302- this . _changedProperties . Select ( s => _allProperties [ s ] ) . ToArray ( ) ;
302+ _changedProperties . Intersect ( _updatableProperties ) . Select ( s => _allProperties [ s ] ) . ToArray ( ) ;
303303 foreach ( PropertyAccessor < TStructuralType > propertyToCopy in propertiesToCopy )
304304 {
305305 propertyToCopy . Copy ( _instance , original ) ;
@@ -509,12 +509,11 @@ private void InitializeProperties(IEnumerable<string> updatableProperties)
509509
510510 if ( updatableProperties != null )
511511 {
512- _updatableProperties = new HashSet < string > ( updatableProperties ) ;
513- _updatableProperties . IntersectWith ( _allProperties . Keys ) ;
512+ _updatableProperties = updatableProperties . Intersect ( _allProperties . Keys ) . ToList ( ) ;
514513 }
515514 else
516515 {
517- _updatableProperties = new HashSet < string > ( _allProperties . Keys ) ;
516+ _updatableProperties = new List < string > ( _allProperties . Keys ) ;
518517 }
519518
520519 if ( _dynamicDictionaryPropertyinfo != null )
@@ -629,7 +628,7 @@ private bool TrySetPropertyValueInternal(string name, object value)
629628 throw Error . ArgumentNull ( "name" ) ;
630629 }
631630
632- if ( ! _updatableProperties . Contains ( name ) )
631+ if ( ! ( _allProperties . ContainsKey ( name ) && _updatableProperties . Contains ( name ) ) )
633632 {
634633 return false ;
635634 }
@@ -659,7 +658,7 @@ private bool TrySetNestedResourceInternal(string name, object deltaNestedResourc
659658 throw Error . ArgumentNull ( "name" ) ;
660659 }
661660
662- if ( ! _updatableProperties . Contains ( name ) )
661+ if ( ! ( _allProperties . ContainsKey ( name ) && _updatableProperties . Contains ( name ) ) )
663662 {
664663 return false ;
665664 }
0 commit comments