public bool EntityFunction(int key, [FromODataUri] EdmEntityObject customer) { Assert.NotNull(customer); dynamic result = customer; Assert.Equal("NS.Customer", customer.GetEdmType().FullName()); // entity call if (key == 9) { Assert.Equal(91, result.Id); Assert.Equal("John", result.Name); dynamic address = result.Location; EdmComplexObject addressObj = Assert.IsType <EdmComplexObject>(address); Assert.Equal("NS.Address", addressObj.GetEdmType().FullName()); Assert.Equal("NE 24th St.", address.Street); Assert.Equal("Redmond", address.City); } else { // entity reference call Assert.Equal(8, result.Id); Assert.Equal("Id", String.Join(",", customer.GetChangedPropertyNames())); Assert.Equal("Name,Location", String.Join(",", customer.GetUnchangedPropertyNames())); } return(true); }
public IHttpActionResult PatchCustomerBySSN([FromODataUri] string ssnKey, EdmEntityObject delta) { IList <string> changedPropertyNames = delta.GetChangedPropertyNames().ToList(); IEdmEntityObject originalCustomer = null; foreach (var customer in AlternateKeysDataSource.Customers) { object value; if (customer.TryGetPropertyValue("SSN", out value)) { string stringKey = (string)value; if (ssnKey == stringKey) { originalCustomer = customer; } } } if (originalCustomer == null) { return(NotFound()); } object nameValue; delta.TryGetPropertyValue("Name", out nameValue); //Assert.NotNull(nameValue); //string strName = Assert.IsType<string>(nameValue); dynamic original = originalCustomer; //original.Name = strName; original.Name = nameValue; return(Ok(originalCustomer)); }
/// <summary> /// Обновление сущности (свойства могут быть заданы частично, т.е. указывать можно значения только измененных свойств). /// Если сущности с заданным ключом нет в БД происходит Upsert (в соответствии со стандартом). /// </summary> /// <param name="key"> Ключ обновляемой сущности. </param> /// <param name="edmEntity">Обновляемая сущность. </param> /// <returns>Обновлённая сущность.</returns> public HttpResponseMessage Patch([FromODataUri] Guid key, [FromBody] EdmEntityObject edmEntity) { try { if (key == null) { throw new ArgumentNullException("key"); } if (edmEntity == null) { edmEntity = ReplaceOdataBindNull(); } IEdmEntityType entityType = (IEdmEntityType)edmEntity.ActualEdmType; var dictionary = Request.Properties.ContainsKey(ExtendedODataEntityDeserializer.Dictionary) ? (Dictionary <string, object>)Request.Properties[ExtendedODataEntityDeserializer.Dictionary] : new Dictionary <string, object>(); foreach (var prop in entityType.Properties()) { if (!dictionary.ContainsKey(prop.Name) && edmEntity.GetChangedPropertyNames().Contains(prop.Name) && prop is EdmNavigationProperty) { return(Request.CreateResponse(System.Net.HttpStatusCode.BadRequest, "Error processing request stream. Deep updates are not supported in PUT or PATCH operations.")); } if (dictionary.ContainsKey(prop.Name) && dictionary[prop.Name] == null && (!prop.Type.IsNullable || prop.Type.IsCollection())) { return(Request.CreateResponse(System.Net.HttpStatusCode.BadRequest, $"The property {prop.Name} can not be null.")); } } DataObject obj = UpdateObject(edmEntity, key); ExecuteCallbackAfterUpdate(obj); var responseForPreferMinimal = TestPreferMinimal(); if (responseForPreferMinimal != null) { return(responseForPreferMinimal); } if (!Request.Headers.Contains("Prefer")) { return(Request.CreateResponse(System.Net.HttpStatusCode.NoContent)); } edmEntity = GetEdmObject(_model.GetEdmEntityType(type), obj, 1, null, null); var result = Request.CreateResponse(System.Net.HttpStatusCode.OK, edmEntity); result.Headers.Add("Preference-Applied", "return=representation"); return(result); } catch (Exception ex) { return(InternalServerErrorMessage(ex)); } }
public IHttpActionResult GetCustomer(int key, [FromODataUri] EdmEntityObject customer) { Assert.NotNull(customer); StringBuilder sb = new StringBuilder(); IEnumerable <string> propertyNames = customer.GetChangedPropertyNames(); foreach (string name in propertyNames) { object value; customer.TryGetPropertyValue(name, out value); sb.Append(name + "=").Append(value).Append(","); } return(Ok("GetCustomer(" + sb.ToString() + ")")); }
public ITestActionResult PatchCustomerBySSN([FromODataUri] string ssnKey, [FromBody] EdmEntityObject delta) { Assert.Equal("SSN-6-T-006", ssnKey); IList <string> changedPropertyNames = delta.GetChangedPropertyNames().ToList(); Assert.Single(changedPropertyNames); Assert.Equal("Name", String.Join(",", changedPropertyNames)); IEdmEntityObject originalCustomer = null; foreach (var customer in AlternateKeysDataSource.Customers) { object value; if (customer.TryGetPropertyValue("SSN", out value)) { string stringKey = (string)value; if (ssnKey == stringKey) { originalCustomer = customer; } } } if (originalCustomer == null) { return(NotFound()); } object nameValue; delta.TryGetPropertyValue("Name", out nameValue); Assert.NotNull(nameValue); string strName = Assert.IsType <string>(nameValue); dynamic original = originalCustomer; original.Name = strName; return(Ok(originalCustomer)); }
/// <summary> /// Построение объекта данных по сущности OData. /// </summary> /// <param name="edmEntity"> Сущность OData. </param> /// <param name="key"> Значение ключевого поля сущности. </param> /// <param name="dObjs"> Список объектов для обновления. </param> /// <param name="endObject"> Признак, что объект добавляется в конец списка обновления. </param> /// <returns> Объект данных. </returns> private DataObject GetDataObjectByEdmEntity(EdmEntityObject edmEntity, object key, List <DataObject> dObjs, bool endObject = false) { if (edmEntity == null) { return(null); } IEdmEntityType entityType = (IEdmEntityType)edmEntity.ActualEdmType; Type objType = _model.GetDataObjectType(_model.GetEdmEntitySet(entityType).Name); // Значение свойства. object value; // Получим значение ключа. var keyProperty = entityType.Properties().FirstOrDefault(prop => prop.Name == _model.KeyPropertyName); if (key != null) { value = key; } else { edmEntity.TryGetPropertyValue(keyProperty.Name, out value); } // Загрузим объект из хранилища, если он там есть (используем представление по умолчанию), или создадим, если нет, но только для POST. // Тем самым гарантируем загруженность свойств при необходимости обновления и установку нужного статуса. DataObject obj = ReturnDataObject(objType, value); // Добавляем объект в список для обновления, если там ещё нет объекта с таким ключом. var objInList = dObjs.FirstOrDefault(o => o.__PrimaryKey.ToString() == obj.__PrimaryKey.ToString()); if (objInList == null) { if (!endObject) { // Добавляем объект в начало списка. dObjs.Insert(0, obj); } else { // Добавляем в конец списка. dObjs.Add(obj); } } // Все свойства объекта данных означим из пришедшей сущности, если они были там установлены(изменены). foreach (var prop in entityType.Properties()) { string dataObjectPropName = _model.GetDataObjectProperty(entityType.FullTypeName(), prop.Name).Name; if (edmEntity.GetChangedPropertyNames().Contains(prop.Name)) { // Обработка мастеров и детейлов. if (prop is EdmNavigationProperty) { EdmNavigationProperty navProp = (EdmNavigationProperty)prop; edmEntity.TryGetPropertyValue(prop.Name, out value); EdmMultiplicity edmMultiplicity = navProp.TargetMultiplicity(); // var aggregator = Information.GetAgregatePropertyName(objType); // Обработка мастеров. if (edmMultiplicity == EdmMultiplicity.One || edmMultiplicity == EdmMultiplicity.ZeroOrOne) { if (value != null && value is EdmEntityObject) { EdmEntityObject edmMaster = (EdmEntityObject)value; DataObject master = GetDataObjectByEdmEntity(edmMaster, null, dObjs); Information.SetPropValueByName(obj, dataObjectPropName, master); } else { Information.SetPropValueByName(obj, dataObjectPropName, null); } } // Обработка детейлов. if (edmMultiplicity == EdmMultiplicity.Many) { Type detType = Information.GetPropertyType(objType, dataObjectPropName); DetailArray detarr = (DetailArray)Information.GetPropValueByName(obj, dataObjectPropName); if (value != null && value is EdmEntityObjectCollection) { EdmEntityObjectCollection coll = (EdmEntityObjectCollection)value; if (coll != null && coll.Count > 0) { foreach (var edmEnt in coll) { DataObject det = GetDataObjectByEdmEntity( (EdmEntityObject)edmEnt, null, dObjs, true); if (det.__PrimaryKey == null) { detarr.AddObject(det); } else { detarr.SetByKey(det.__PrimaryKey, det); } } } } else { detarr.Clear(); } } } else { // Обработка собственных свойств объекта (неключевых, т.к. ключ устанавливаем при начальной инициализации объекта obj). if (prop.Name != keyProperty.Name) { Type dataObjectPropertyType = Information.GetPropertyType(objType, dataObjectPropName); edmEntity.TryGetPropertyValue(prop.Name, out value); // Если тип свойства относится к одному из зарегистрированных провайдеров файловых свойств, // значит свойство файловое, и его нужно обработать особым образом. if (FileController.HasDataObjectFileProvider(dataObjectPropertyType)) { IDataObjectFileProvider dataObjectFileProvider = FileController.GetDataObjectFileProvider(dataObjectPropertyType); // Обработка файловых свойств объектов данных. string serializedFileDescription = value as string; if (serializedFileDescription == null) { // Файловое свойство было сброшено на клиенте. // Ассоциированный файл должен быть удален, после успешного сохранения изменений. // Для этого запоминаем метаданные ассоциированного файла, до того как свойство будет сброшено // (для получения метаданных свойство будет дочитано в объект данных). // Файловое свойство типа File хранит данные ассоциированного файла прямо в БД, // соответственно из файловой системы просто нечего удалять, // поэтому обходим его стороной, чтобы избежать лишных вычиток файлов из БД. if (dataObjectPropertyType != typeof(File)) { _removingFileDescriptions.Add(dataObjectFileProvider.GetFileDescription(obj, dataObjectPropName)); } // Сбрасываем файловое свойство в изменяемом объекте данных. Information.SetPropValueByName(obj, dataObjectPropName, null); } else { // Файловое свойство было изменено, но не сброшено. // Если в метаданных файла присутствует FileUploadKey значит файл был загружен на сервер, // но еще не был ассоциирован с объектом данных, и это нужно сделать. FileDescription fileDescription = FileDescription.FromJson(serializedFileDescription); if (!(string.IsNullOrEmpty(fileDescription.FileUploadKey) || string.IsNullOrEmpty(fileDescription.FileName))) { Information.SetPropValueByName(obj, dataObjectPropName, dataObjectFileProvider.GetFileProperty(fileDescription)); // Файловое свойство типа File хранит данные ассоциированного файла прямо в БД, // поэтому после успешного сохранения объекта данных, оссоциированный с ним файл должен быть удален из файловой системы. // Для этого запоминаем описание загруженного файла. if (dataObjectPropertyType == typeof(File)) { _removingFileDescriptions.Add(fileDescription); } } } } else { // Преобразование типов для примитивных свойств. if (value is DateTimeOffset) { value = ((DateTimeOffset)value).UtcDateTime; } if (value is EdmEnumObject) { value = ((EdmEnumObject)value).Value; } Information.SetPropValueByName(obj, dataObjectPropName, value); } } } } } return(obj); }