How to update Model when binding to a ViewModel?
Asked Answered
W

3

15

I have an [HttpPost] action method signature like this:

[HttpPost]
public ActionResult Edit(ExistingPostViewModel model)
{
   // Save the edited Post.
}

Now, in the past (when i didn't use ViewModels, e.g R&D), i had an implementation of an Edit method like this:

[HttpPost]
public ActionResult Edit(Post model)
{
    var existingPost = repo.Find(model.Id);
    TryUpdateModel(existingPost);
    repo.Save(existingPost);  
    return RedirectToAction("Success", existingPost.Id);
}

Which worked great.

But i'm confused how to adapt the above to the ViewModel approach.

If i do this:

TryUpdateModel(existingPost)

With my ViewModel approach, not much happens. No errors, but nothing is being updated because MVC won't know how to update a Post from a ExistingPostViewModel (before it was Post -> Post).

Now, i'm using AutoMapper. So i thought i could map from the ViewModel to the Post, then save the post.

But then im basically overriding everything. Which i don't want to do and defeats the point of the cut down ViewModel.

Can anyone un-confuse me?

This seems like a really common scenario, and i am totally stumped as to how people solve this. I can only see 3 possible solutions:

  1. Don't use a ViewModel in the HTTP POST. As i said i did this in the past for R&D and it works, but now i see how my View's have evolved (validation, simplicity), and i can't compromise that just for the sake of this problem.

  2. Don't use TryUpdateModel. Possibly, but then how would i merge in the changes?

  3. Use left-to-right. Ugh. But at the moment this seems to be the way im leaning.

Someone please give me solution #4! :)

BTW, i'm using ASP.NET MVC 3, Razor and Entity Framework.

Whichever answered 5/5, 2011 at 5:4 Comment(0)
R
2

I actually ran into this exact same issue in a project I'm currently working on. As much as I wasn't a fan of it, I ended up doing the left to right approach and manually mapping my viewmodel data back to my entity.

The only nice thing about this approach is it does give you more control. Since I started using more compound viewmodels, where you actually have fields from more than one entity in your viewmodel, it started making more sense to do things this way.

I'm also using AutoMapper, and you're absolutely right, it does get awkward when you're trying to do a simple update operation. Wish I had some super clever workaround for you, but the "old fashioned way" seems to get the job done best for the work I've been doing.

Rabush answered 5/5, 2011 at 12:41 Comment(2)
Noooo.. :) I don't mind doing a left to right every now and then, but this means EVERY update page will need to do it. There really should be a generic/simple way to do this. I use a ViewModel on every View. So every View that requires an update to the database with need L-R. Plus i'm now to need a ton of hidden fields too. My head hurts.... :(Whichever
Was waiting in the hope someone else would come along and tell us there is a better way. But i guess there isn't. :( +1 and accepted.Whichever
A
1

Not sure if this will help, but it is working for me. I have my underlying domain table as a Visitor Object. My viewmodel contains the Visitor Object plus a couple of IEnumerables for dropdowns.

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult Edit(int id)

    {
        Visitor Visitor = new Visitor();
        Visitor = db.Visitors.FirstOrDefault(v => v.VisitorID == id);

        UpdateModel(Visitor, "Visitor");

        db.SaveChanges();
        return RedirectToAction("Index");

    }

The UpdateModel works off my viewmodel because of the "Visitor" string telling it what values to compare.

Allomorphism answered 18/4, 2016 at 20:1 Comment(0)
H
0

For simple things where you don't have to run any controls prior to implementing the update what you are doing is okay (db.get(), and then update).

When things get complicated, you have to load the entity, and then select and apply user's changes from the view model, property by property. In those cases, you end up writing Update methods, which gets the new data as input, and then you load the existing entity, then compare states, and take the required actions based on the view model data. Actually in this case, probably you wont have an Update method but will have behaviors, like CancelPost, AddComment, EditPost (which also logs the edit reason), AddTagsToPost etc.

Honeyman answered 5/5, 2011 at 12:58 Comment(1)
Yeah, i've got behaviour methods like AddComment. But this is a basic CRUD page where i just want to update the existing object with the values i have provided in the incoming ViewModel. It should be simple, i can't believe i have to manually compare the states of the properties. This also means i'll need hidden fields all over the form.Whichever

© 2022 - 2024 — McMap. All rights reserved.