public async Task TestEntityFilterReturnsTask() { var container = new RestierContainerBuilder(typeof(TestEntityFilterReturnsTaskApi)); var provider = container.BuildContainer(); var api = provider.GetService<ApiBase>(); DataModificationItem<Customer> createCustomer = new DataModificationItem<Customer>( "Customers", typeof(Customer), null, DataModificationItemAction.Insert, null, null, new Dictionary<string, object>() { {"CustomerID", "NEW01"}, {"CompanyName", "New Cust"}, }); await api.SubmitAsync(new ChangeSet(new ChangeSetItem[] { createCustomer })); NorthwindContext ctx = new NorthwindContext(); #if EF7 Customer newCustomer = await ctx.Customers.FirstOrDefaultAsync(e => e.CustomerID == "NEW01"); #else Customer newCustomer = await ctx.Customers.FindAsync("NEW01"); #endif // The "OnInserting" should have been appended by the OnInsertingCustomers filter Assert.Equal("New CustOnInserting", newCustomer.CompanyName); ctx.Customers.Remove(newCustomer); await ctx.SaveChangesAsync(); }
public async Task ComplexTypeUpdate() { // Arrange var container = new RestierContainerBuilder(typeof(LibraryApi)); var provider = container.BuildContainer(); var libraryApi = provider.GetService<ApiBase>(); var item = new DataModificationItem( "Readers", typeof(Person), null, DataModificationItemAction.Update, new Dictionary<string, object> { { "Id", new Guid("53162782-EA1B-4712-AF26-8AA1D2AC0461") } }, new Dictionary<string, object>(), new Dictionary<string, object> { { "Addr", new Dictionary<string, object> { { "Zip", "332" } } } }); var changeSet = new ChangeSet(new[] { item }); var sc = new SubmitContext(libraryApi.Context, changeSet); // Act var changeSetPreparer = libraryApi.Context.GetApiService<IChangeSetInitializer>(); await changeSetPreparer.InitializeAsync(sc, CancellationToken.None); var person = item.Resource as Person; // Assert Assert.NotNull(person); Assert.Equal("332", person.Addr.Zip); }
private void SetValues(DbEntityEntry dbEntry, DataModificationItem item, Type resourceType) { if (item.IsFullReplaceUpdateRequest) { // The algorithm for a "FullReplaceUpdate" is taken from ObjectContextServiceProvider.ResetResource // in WCF DS, and works as follows: // - Create a new, blank instance of the entity. // - Copy over the key values and set any updated values from the client on the new instance. // - Then apply all the properties of the new instance to the instance to be updated. // This will set any unspecified properties to their default value. object newInstance = Activator.CreateInstance(resourceType); SetValues(newInstance, resourceType, item.ResourceKey); SetValues(newInstance, resourceType, item.LocalValues); dbEntry.CurrentValues.SetValues(newInstance); } else { foreach (KeyValuePair<string, object> propertyPair in item.LocalValues) { DbPropertyEntry propertyEntry = dbEntry.Property(propertyPair.Key); object value = propertyPair.Value; if (value == null) { // If the property value is null, we set null in the item too. propertyEntry.CurrentValue = null; continue; } Type type = null; if (propertyEntry.CurrentValue != null) { type = propertyEntry.CurrentValue.GetType(); } else { // If property does not have value now, will get property type from model var propertyInfo = dbEntry.Entity.GetType().GetProperty(propertyPair.Key); type = propertyInfo.PropertyType; } if (propertyEntry is DbComplexPropertyEntry) { var dic = value as IReadOnlyDictionary<string, object>; if (dic == null) { throw new NotSupportedException(string.Format( CultureInfo.InvariantCulture, Resources.UnsupportedPropertyType, propertyPair.Key)); } value = Activator.CreateInstance(type); SetValues(value, type, dic); } propertyEntry.CurrentValue = ConvertToEfValue(type, value); } } }
private static async Task<object> FindResource( SubmitContext context, DataModificationItem item, CancellationToken cancellationToken) { IQueryable query = context.ApiContext.GetQueryableSource(item.ResourceSetName); query = item.ApplyTo(query); QueryResult result = await context.ApiContext.QueryAsync(new QueryRequest(query), cancellationToken); object resource = result.Results.SingleOrDefault(); if (resource == null) { throw new ResourceNotFoundException(Resources.ResourceNotFound); } // This means no If-Match or If-None-Match header if (item.OriginalValues == null || item.OriginalValues.Count == 0) { return resource; } resource = item.ValidateEtag(result.Results.AsQueryable()); return resource; }
private async Task<IHttpActionResult> Update( EdmEntityObject edmEntityObject, bool isFullReplaceUpdate, CancellationToken cancellationToken) { ODataPath path = this.GetPath(); IEdmEntitySet entitySet = path.NavigationSource as IEdmEntitySet; if (entitySet == null) { throw new NotImplementedException(Resources.UpdateOnlySupportedOnEntitySet); } var propertiesInEtag = await this.GetOriginalValues(entitySet); if (propertiesInEtag == null) { throw new PreconditionRequiredException(Resources.PreconditionRequired); } // In case of type inheritance, the actual type will be different from entity type // This is only needed for put case, and does not need for patch case // For put request, it will create a new, blank instance of the entity. // copy over the key values and set any updated values from the client on the new instance. // Then apply all the properties of the new instance to the instance to be updated. // This will set any unspecified properties to their default value. var expectedEntityType = path.EdmType; var actualEntityType = path.EdmType as IEdmStructuredType; if (edmEntityObject.ActualEdmType != null) { expectedEntityType = edmEntityObject.ExpectedEdmType; actualEntityType = edmEntityObject.ActualEdmType; } DataModificationItem updateItem = new DataModificationItem( entitySet.Name, expectedEntityType.GetClrType(Api), actualEntityType.GetClrType(Api), DataModificationItemAction.Update, RestierQueryBuilder.GetPathKeyValues(path), propertiesInEtag, edmEntityObject.CreatePropertyDictionary(actualEntityType, api, false)); updateItem.IsFullReplaceUpdateRequest = isFullReplaceUpdate; RestierChangeSetProperty changeSetProperty = this.Request.GetChangeSet(); if (changeSetProperty == null) { ChangeSet changeSet = new ChangeSet(); changeSet.Entries.Add(updateItem); SubmitResult result = await Api.SubmitAsync(changeSet, cancellationToken); } else { changeSetProperty.ChangeSet.Entries.Add(updateItem); await changeSetProperty.OnChangeSetCompleted(this.Request); } return this.CreateUpdatedODataResult(updateItem.Resource); }
/// <summary> /// Handles a DELETE request to delete an entity. /// </summary> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The task object that contains the deletion result.</returns> public async Task<IHttpActionResult> Delete(CancellationToken cancellationToken) { ODataPath path = this.GetPath(); IEdmEntitySet entitySet = path.NavigationSource as IEdmEntitySet; if (entitySet == null) { throw new NotImplementedException(Resources.DeleteOnlySupportedOnEntitySet); } var propertiesInEtag = await this.GetOriginalValues(entitySet); if (propertiesInEtag == null) { throw new PreconditionRequiredException(Resources.PreconditionRequired); } DataModificationItem deleteItem = new DataModificationItem( entitySet.Name, path.EdmType.GetClrType(Api), null, DataModificationItemAction.Remove, RestierQueryBuilder.GetPathKeyValues(path), propertiesInEtag, null); RestierChangeSetProperty changeSetProperty = this.Request.GetChangeSet(); if (changeSetProperty == null) { ChangeSet changeSet = new ChangeSet(); changeSet.Entries.Add(deleteItem); SubmitResult result = await Api.SubmitAsync(changeSet, cancellationToken); } else { changeSetProperty.ChangeSet.Entries.Add(deleteItem); await changeSetProperty.OnChangeSetCompleted(this.Request); } return this.StatusCode(HttpStatusCode.NoContent); }
/// <summary> /// Handles a POST request to create an entity. /// </summary> /// <param name="edmEntityObject">The entity object to create.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>The task object that contains the creation result.</returns> public async Task<IHttpActionResult> Post(EdmEntityObject edmEntityObject, CancellationToken cancellationToken) { if (!this.ModelState.IsValid) { return BadRequest(this.ModelState); } ODataPath path = this.GetPath(); IEdmEntitySet entitySet = path.NavigationSource as IEdmEntitySet; if (entitySet == null) { throw new NotImplementedException(Resources.InsertOnlySupportedOnEntitySet); } // In case of type inheritance, the actual type will be different from entity type var expectedEntityType = path.EdmType; var actualEntityType = path.EdmType as IEdmStructuredType; if (edmEntityObject.ActualEdmType != null) { expectedEntityType = edmEntityObject.ExpectedEdmType; actualEntityType = edmEntityObject.ActualEdmType; } DataModificationItem postItem = new DataModificationItem( entitySet.Name, expectedEntityType.GetClrType(Api), actualEntityType.GetClrType(Api), DataModificationItemAction.Insert, null, null, edmEntityObject.CreatePropertyDictionary(actualEntityType, api, true)); RestierChangeSetProperty changeSetProperty = this.Request.GetChangeSet(); if (changeSetProperty == null) { ChangeSet changeSet = new ChangeSet(); changeSet.Entries.Add(postItem); SubmitResult result = await Api.SubmitAsync(changeSet, cancellationToken); } else { changeSetProperty.ChangeSet.Entries.Add(postItem); await changeSetProperty.OnChangeSetCompleted(this.Request); } return this.CreateCreatedODataResult(postItem.Resource); }