How do I update a view model from an edit page in MVC3?

11,968

Solution 1

Your ViewModel is not an entity. You should map your ViewModel to your entity, then set the entity's state to modified.

Basically, this means that you should set your entity values with your view model values. You can use AutoMapper or handle it manually:

    [HttpPost]
    public ActionResult Edit(ClientContactViewModel model)
    {
        if (ModelState.IsValid)
        {
            ClientContact contact = db.ClientPersons.Include("Person")
                                    .Where(x => x.ClientPersonId == model.ClientPersonId)
                                    .SingleOrDefault();
            contact.FirstName = model.FirstName;
            // etc
            db.Entry(contact).State = EntityState.Modified;
            db.SaveChanges();
            return RedirectToAction("Index");
        }
        return View(model);
    }

See http://lostechies.com/jimmybogard/2009/06/30/how-we-do-mvc-view-models/ for an excellent approach to using ViewModels in MVC.

Also, I would highly recommend not doing any data access in your ViewModel. Do that in your Controller, or even better, in a Repository that is used by your Controller. Model binding doesn't play well with models that have logic (i.e they shouldn't contain anything more than simple get/set properties).

Solution 2

You need to move your models' properties to the viewmodel in the GET action. In the POST action, get your original models from the db, update the models with the data from the view model, and then save changes. Your models are essentially representations of tables in your database. Your view model is just what is shown on the screen.

[HttpPost] 
    public ActionResult Edit(ClientContactViewModel model) 
    { 
        if (ModelState.IsValid) 
        { 

           var client = db.Client.Where(c => c.Id = model.ClientPersonId);
           client.FirstName = model.FirstName;

           ...etc through all your properties and other models...


            db.Entry(model).State = EntityState.Modified; 
            db.SaveChanges(); 
            return RedirectToAction("Index"); 
        } 
        return View(model); 
    } 

There are slicker ways to do this, but this represents the idea without abstractions.

Share:
11,968
Barrett Kuethen
Author by

Barrett Kuethen

Updated on June 15, 2022

Comments

  • Barrett Kuethen
    Barrett Kuethen almost 2 years

    I have three models that are coming together to create one view model and I'd like to be able to edit that view model when clicking "edit". I can't find a straight forward example of how this works (anywhere).

    I'm not sure if I'm going down the right path. I am able to get the view with the data. At this point, I am unable to save it.

    Any help would be appreciated.

    Thanks!

    Models:

        public class Person
    {
        [Key]
        public int Id { get; set; }
    
        [MaxLength(20)]
        [Required(ErrorMessage = "First name is required.")]
        public string FirstName { get; set; }
    
        [MaxLength(20)]
        [Required(ErrorMessage = "Last name is required.")]
        public string LastName { get; set; }
        [MaxLength(40)]
        [Required(ErrorMessage = "Email is required.")]
        public string Email { get; set; }
        [MaxLength(20)]
        [DataType(DataType.PhoneNumber)]
        public string Phone { get; set; }
    
        public bool Active { get; set; }
    }
    
    
        public class ClientContact
    {
        [Key]
        [ForeignKey("Person")]
        public int ClientPersonId { get; set; }
        public int ClientId { get; set; }
        [MaxLength(40)]
        public string Title { get; set; }
    
        public Person Person { get; set; }
        [ForeignKey("ClientId")]
        public Client Client { get; set; }
    }
    
        public class Client
    {
        [Key]
        public int ClientId { get; set; }
        public string Name { get; set; }
        public bool Active {get;set;}
    
    }
    

    View Model:

        public class ClientContactViewModel
    {
    
        private SimplexDB db = new SimplexDB();
    
    
        public ClientContactViewModel()
        { 
    
        }
    
    
        public ClientContactViewModel(int id)
        {
            ClientPersonId = id;
            InitializeClientContact();
        }
    
        public int ClientPersonId { get; set; }
    
    
        [Display(Name = "First Name")]
        public string FirstName { get; set; }
        [Display(Name = " Last Name")]
        public string LastName { get; set; }
        [Display(Name = "Title")]
        public string Title { get; set; }
        [Display(Name = "Email Address")]
        public string Email { get; set; }
        [Display(Name = "Phone")]
        public string Phone { get; set; }
        [Display(Name = "Client Name")]
        public int ClientId { get; set; }
    
    
        public SelectList Clients
        {
            get
            {
                return new SelectList(db.Clients, "ClientId", "Name");
    
            }
        }
    
        private void InitializeClientContact()
        {
            var contact = db.ClientPersons.Include("Person").Where(x => x.ClientPersonId == ClientPersonId).SingleOrDefault();
            if (contact != null)
            {
                FirstName = contact.Person.FirstName;
                LastName = contact.Person.LastName;
                Title = contact.Title;
                Email = contact.Person.Email;
                Phone = contact.Person.Phone;
                ClientId = contact.ClientId;
    
            }
        }
    
    
    
    }
    

    Controller:

                    public class ClientContactController : Controller
        {
            private database db = new database();
    
    //
            // GET: /ClientContact/Edit/5
    
            public ActionResult Edit(int id)
            {
                return View(new ClientContactViewModel(id));
            }
    
            //
            // POST: /ClientContact/Edit/5
    
            [HttpPost]
            public ActionResult Edit(ClientContactViewModel model)
            {
                if (ModelState.IsValid)
                {
                    db.Entry(model).State = EntityState.Modified;
                    db.SaveChanges();
                    return RedirectToAction("Index");
                }
                return View(model);
            }
    }
    

    I get an error at the db.Entry(model).State... "The entity type ClientContactViewModel is not part of the model for the current context."