Building view models for use within your MVC solution is great to combine objects for a strongly typed view. And I have been all about them. I just encountered a situation where I needed to update values for specific models contained within the view model. Getting the view model back from the view was the easy part thanks to MVC.
This immediately didn't told me it wouldn't work. Update what model? and in what context??? The solution I am making rebuilds the context each get/post. Is there a better way, probably, but this is what I do for now. After searching for some .net built in solutions, I started creating an update function that would copy values from the modified object into a context object, allow Entity Framework to detect the change and commit. First round looked like this.
I created a specific Interface under my current IUser and named it IUserDetailsCompare. Then instead of using the User type during my reflection loop I told the loop to evaluate the Interface. Done!
[Authorize] public ActionResult Index() { var context = new Context(); var repo = new UserRepository(context); var user = repo.GetUserByEmail(User.Identity.Name); var account = new Account { User = user }; return View(account); }
In a perfect world I would have loved to just have done this
[Authorize]
[HttpPost]
public ActionResult Index(Account account)
{
UpdateModel(account.User);
repo.Save();
return RedirectToAction("Index");
}
This immediately didn't told me it wouldn't work. Update what model? and in what context??? The solution I am making rebuilds the context each get/post. Is there a better way, probably, but this is what I do for now. After searching for some .net built in solutions, I started creating an update function that would copy values from the modified object into a context object, allow Entity Framework to detect the change and commit. First round looked like this.
public void Update(User copyToUser, User copyFromUser) { var type = typeof(User); foreach (var pi in type.GetProperties()) { var copyValue = copyFromUser.GetType().GetProperty(pi.Name).GetValue(copyFromUser, null); copyToUser.GetType().GetProperty(pi.Name).SetValue(copyToUser, copyValue,null); } }This was working great, except it was modifying values related to identity and references! And then creating new objects! ACK! While I could have hard coded specific property names to either be skipped or evaluated, I wanted a more concrete and testable way.
I created a specific Interface under my current IUser and named it IUserDetailsCompare. Then instead of using the User type during my reflection loop I told the loop to evaluate the Interface. Done!
public interface IUser { long Id { get; set; } string Email { get; set; } string NameFirst { get; set; } string NameLast { get; set; } DateTime DateJoined { get; set; } Guid Ref { get; set; } bool Active { get; set; } bool Disclaimer { get; set; } } public interface IUserDetailsCompare { string NameFirst { get; set; } string NameLast { get; set; } } public void Update(User copyToUser, User copyFromUser) { var type = typeof(IUserDetailsCompare); foreach (var pi in type.GetProperties()) { var copyValue = copyFromUser.GetType().GetProperty(pi.Name).GetValue(copyFromUser, null); copyToUser.GetType().GetProperty(pi.Name).SetValue(copyToUser, copyValue,null); } }I consider this a huge win in my strive to follow a more TDD approach.