public void SetValue(object targetResource, string propertyName, object propertyValue) { CustomUtils.CheckArgumentNotNull(targetResource, "targetResource"); CustomUtils.CheckArgumentNotNull(propertyName, "propertyName"); var property = GetProperty(targetResource.GetType(), propertyName); if (IsComplexType(property.PropertyType)) { // we treat complex types as value types, an inherit part of an entity type, // they cannot be null, have no separate metadata, always exist and // by design complex type properties have no setters // // we can relax these constraints later, but now change detection // logic in custom object context depends on it if (null == propertyValue) { throw new ArgumentNullException(String.Format( "Value for complex type property '{0}' cannot be null.", propertyName )); } object currentComplexValue = property.GetValue(targetResource, null); CopyComplexTypeObject(currentComplexValue, propertyValue); return; } CustomMemberType entityMember; if (TryGetEntityMember(targetResource, propertyName, out entityMember)) { if (entityMember is CustomNavigationPropertyType) { throw new InvalidOperationException(String.Format( "Given property '{0}' of entity object '{1}' is a navigation " + "property of type '{2}'. SetValue() is not supposed for " + "changing navigation properties. Use SetReference() or " + "AddReferenceToCollection() methods.", propertyName, targetResource, entityMember.ClrType )); } Debug.Assert(entityMember is CustomPropertyType); CustomPropertyType entityProperty = (CustomPropertyType)entityMember; if (null != entityProperty.ForeignKeyConstraint) { // attempt to set a foreign key property is incorrect in the world of our custom // data model because there is no setter for such properties at all and the getter // simply returns value of a primary key property from the primary end entity using // corresponding navigation property // get // { // if(null == _primaryEnd) // { // return default(int); // } // return _primaryEnd.Id; // } // // silently return from SetValue without error reporting for compatibility // with existing tests return; } if (entityProperty.IsPrimaryKey) { // all our primary keys are store generated and have internal setter, but // test framework for Astoria suppose to be able to set primary keys and // then use same values to query the object; we allow it here to be // compatible with the existing tests; for objects with initialized primary keys // the custom object context will actually queue an update operation, but not insert entityProperty.SetValue(targetResource, propertyValue); return; } } else { Debug.Assert(IsComplexType(targetResource.GetType())); } if (null == property.GetSetMethod() || !property.CanWrite) { throw new InvalidOperationException(String.Format( "Property '{0}' of resource type '{1}' is not writable.", propertyName, targetResource.GetType().Name )); } property.SetValue(targetResource, propertyValue, null); }