Paul
Paul

Reputation: 36329

ASP.NET MVC 4 error updating entity framework models with related entities

I feel like this should be a pretty common thing to do. I have a model with a related object on it. Let's say it's a User and a user has one Role.

public class User
{
  public int Id { get; set; }
  public virtual Role Role { get; set; }
  /* other stuff that saves fine */
}

public class Role
{
  public int Id {get;set;}
  public string Name { get;set;}
}

So if I save a new user, or if I edit a user (but don't change his Role), I have no issues. If I have a user without a role, and add a role to him, again no problem (though I manually lookup the role and assign it). If I try and change a role, I get a modelstate error on the Role property that the ID is part of the object's key and can't be changed. So how do folks go about making updates like this? Whitelist the simple values and then manually update the Role?

My controller code in question is here:

[HttpPost]
public ActionResult Save(int id, FormCollection form)
{
   var user = data.Users.FirstOrDefault(d=> d.Id == id);

   if (user != null)
   {
      TryUpdateModel(user, form.ToValueProvider());
      if (!ModelState.IsValid)
      {
         var messages = ModelState.Values.Where(m => m.Errors.Count() > 0).SelectMany(m=>m.Errors).Select(e => e.ErrorMessage);
         if (Request.IsAjaxRequest())
              return Json(new { message = "Error!", errors = messages });
         return RedirectToAction("index"); // TODO: more robust Flash messaging
      }

      updateDependencies(user);
     /* negotiate response */
   }
}

I'll probably just do it manually for now, but it seems like a scenario that I would have expected to work out of the box, at least to some degree.

Upvotes: 0

Views: 661

Answers (1)

Marthijn
Marthijn

Reputation: 3392

Your User model should have a foreign key:

public int? RoleId { get; set; }
public virtual Role Role { get; set; }

You can assign a Role.Id to this value, or make it null when the user does not have a role.

I'm also not sure if your Save function is correct. I'm always using this pattern (not sure if it is correct either...), but of course it depends on the data you post to the server:

[HttpPost]    
public ActionResult Save(User model)
{
  if (ModelState.IsValid)
  {
    // Save logic here, for updating an existing entry it is something like:
    context.Entry(model).State = EntityState.Modified;
    context.SaveChanges();
    return View("Success");
  }
  return View("Edit", model);
}

Upvotes: 2

Related Questions