Ryan Mendoza
Ryan Mendoza

Reputation: 950

Web API 2: Updating Navigational Properites (Entities)

I am looking for some guidance with Web API functionality that was a breeze in MVC in regards to updating entities that have navigational properties.

In MVC, it was accomplished as:

    [AcceptVerbs(HttpVerbs.Post)]
    [ValidateAntiForgeryToken]
    public virtual async Task<ActionResult> Update(Page page)
    {
        Guard.IsNotNull(page, "page");

        var pageToUpdate = await this.repository.Query.Include(p => p.Tags).Include(p => p.Name).SingleOrDefaultAsync(p => p.Pk == page.Pk);

        if (pageToUpdate == null)
        {
            return this.RedirectToRoute(H.Constants.Routes.Error.Index, new
                                                                        {
                                                                            view = H.Constants.Views.Error.ViewPages.NotFound
                                                                        });
        }

        if (this.TryUpdateModel(pageToUpdate))
        {
            this.repository.BeginTransaction();

            this.repository.Update(pageToUpdate); // Updates related entities!

            await this.repository.CommitTransactionAsync();

            return this.RedirectToRoute(H.Constants.Routes.Data.Read);
        }

        return this.View(H.Constants.Views.FolderNames.ViewPages.FormatWith(H.Constants.Views.Data.ViewPages.Update), pageToUpdate);
    }

All navigational properties would be updated, and life was well.

When attempting this exact thing in Web API, not so much. The related entities are not updated. Example:

    [HttpPatch]
    [HttpPut]
    public virtual async Task<IHttpActionResult> Update(int pk, Page page)
    {
        Guard.IsNotNegativeOrZero(pk, "pk");

        if (this.ModelState.IsValid)
        {
            if (page.Pk == pk)
            {
                try
                {
                    this.repository.BeginTransaction();

                    this.repository.Update(page); // Doesn't update related entities.

                    await this.repository.CommitTransactionAsync();

                    return this.StatusCode(HttpStatusCode.NoContent);
                }
                catch (DbUpdateConcurrencyException dbUpdateConcurrencyException)
                {
                    if (this.repository.Query.Any(p => p.Pk == pk))
                    {
                        return this.InternalServerError(dbUpdateConcurrencyException);
                    }

                    return this.NotFound();
                }
            }

            return this.BadRequest();
        }

        return this.BadRequest(this.ModelState);
    }

Is this possible to do today in Web API? Or is Web API currently an incomplete Microsoft product?

Edit: Updated with example and not referencing WCF

Upvotes: 0

Views: 461

Answers (1)

anon
anon

Reputation:

TryUpdateModel doesn't exist in WebAPI. You may also find you have issues with seralization of entities. For both those reasons I use AutoMapper to map ViewModels onto EF entities and you can use Mappings in automapper to deal with your navigation properites.

The web API method looks something like this:

    public HttpResponseMessage Post(MyViewModel model)
    {
        if (someValidationCheckHere)
            return new HttpResponseMessage(HttpStatusCode.BadRequest);

        _myService.Update(Mapper.Map<MyViewModel, MyEntity>(model));

        return new HttpResponseMessage(HttpStatusCode.OK);
    }

As others have said the service and ultimately the repository does the update. In this example I'm ignoring the navigation property using automapper, but you can configure automapper to handle them how you like:

        Mapper.CreateMap<MyViewModel, MyEntity>()
            .ForMember(x => x.NavigationProperty, opt => opt.Ignore());

I set up all my mappings in a static class called on application_start in global.asax.

Upvotes: 2

Related Questions