7

I have 2 projects - a class library containing an EDM Entity Framework model and a seperate ASP.NET MVC project.

I'm having problems with how your suppose to edit and save changes to an entity using MVC. In my controller I have:

public class UserController : Controller
    {
        public ActionResult Edit(int id)
        {
            var rep = new UserRepository();

            var user = rep.GetById(id);

            return View(user);
        }

        [HttpPost]
        public ActionResult Edit(User user)
        {
            var rep = new UserRepository();

            rep.Update(user);

            return View(user);
        }
    }

My UserRepository has an Update method like this:

public void Update(User user)
{
     using (var context = new PDS_FMPEntities())
     {
         context.Users.Attach(testUser);
         context.ObjectStateManager.ChangeObjectState(testUser, EntityState.Modified);
         context.SaveChanges();
     }
}

Now, when I click 'Save' on the edit user page, the parameter user only contains two values populated: Id, and FirstName. I take it that is due to the fact that I'm only displaying those two properties in the view.

My question is this, if I'm updating the user's firstname, and then want to save it, what am I suppose to do about the other User properties which were not shown on the view, since they now contain 0 or NULL values in the user object?

I've been reading a lot about using stub entities, but I'm getting nowhere fast, in that none of the examples I've seen actually work. i.e. I keep getting EntityKey related exceptions.

Can someone point me to a good tutorial/example of how to update EF 4 entities using a repository class, called by an MVC front-end?

Kara
  • 6,115
  • 16
  • 50
  • 57
Jason Evans
  • 28,906
  • 14
  • 90
  • 154

6 Answers6

2

I would retrieve the user from the database and update that entity. EF can't just magically know which values are supposed to be modified and which aren't.

If you're concerned about concurrency issues you would need to store the timestamp in the view - usually as a hidden form value.

Jaco Pretorius
  • 24,380
  • 11
  • 62
  • 94
1

OK, after some trial and error, I look to have found a solution. Here is my updated Update method in the UserRepository:

public void Update(User user)
{
    using (this.Context)
    {
        var tempUser = new User { usr_id = user.usr_id };

        this.Context.Users.Attach(tempUser);
        this.Context.ApplyCurrentValues("Users", user);
        this.Context.SaveChanges();
    }
}

Some of other examples I tried were very close to the above, but just missed the mark.

Jason Evans
  • 28,906
  • 14
  • 90
  • 154
  • 2
    @Jason Evans - that is referred to as the stub technique, and only works for scalar properties. If you have a navigational property such as `User.Addresses` which you are binding to in your View, the above won't update the addresses. I would advise you retrieving the User from the DB again, then using `TryUpdateModel` to update the object. See my recent question/answer here for more info: http://stackoverflow.com/questions/4653834/asp-net-mvc-ef4-poco-repository-how-to-update-relationships/4666466#4666466 – RPM1984 Jan 12 '11 at 11:00
  • @RPM1984 - That would save hassle with the navigational properties. The one concern I have with TryUpdateModel() is design. I'm trying to ensure that I can use a repository to deal with getting/saving/deleting of stuff. By using TryUpdateModel(), do you have suggestions of good design on how to code this? I just don't want the controller to deal with any database related code if you see what I mean. – Jason Evans Jan 12 '11 at 11:14
  • No, not sure what you mean. I'll take a guess though, create a standard "Save" method in your Repository, which "figures out" if it's a new/existing object (based on ID, for example). So you don't need to call repository.Update or repository.Add. Just TryUpdateModel then Save. If your referring to you don't want your controller touching your entity - i don't understand your concern. Controllers are meant to refresh the model. And all it is doing is updating an "object" - your repository is still concerned with the persistence of said object. – RPM1984 Jan 12 '11 at 11:19
  • @RPM - I just tried a code example and your suggestion works nicely. Likely my concerns about design might not prove to be anything more then lack of experience with MVC, but I'll carry on with the project and see how thing go ith using `TryUpdateModel()`. – Jason Evans Jan 12 '11 at 11:24
  • 1
    Yep - trust me, i've been doing a LOT of ef/mvc lately. And because i'm using POCO's with no change tracking (which means no self tracking entities, no proxy objects, nothing), it's a nightmare to update relationships. Bite the bullet and fetch the record again. Or if your only updating basic properties on the immediate property, `ApplyCurrentValues` is fine. But you need to be consistent. Good luck. :) – RPM1984 Jan 12 '11 at 11:28
  • @RPM1984 stubs work with navigations just fine. It's `ApplyCurrentValues` which is scalar-only. – Craig Stuntz Jan 12 '11 at 18:56
0

I found this tutorial on the asp.net website to be very helpful: Getting Started with EF using MVC - Updating Related Data

The method to pay attention to is TryUpdateModel which will update the related model in the "standard" manner (setting the entity to a modified state and passing everything in) and then will let you customize how certain properties are updated.

I ran into problems with entity keys and this helped me get past those.

carloandaya
  • 196
  • 2
  • 5
0

http://forums.asp.net/p/1697685/5032858.aspx/1?Re+MVC3+edits+to+records+using+Entity+Framework+not+saving+to+the+database

Look the link above I think is a very similar case (with a solution). Good luck

0

This is probably a little late to help answer the question, but maybe it will help some one else. It seems to me that the main problem you are having is caused by the fact that the database context instance that reads an entity is disposed after a page is rendered. So when you try to save it, this is a new instance of a context, which therefore has no knowledge of the previous context call. Entity Framework therefore has to update all rows in the database, because it has no way of knowing which rows were changed.

This being said, the best method that I have found for saving all of the old data, and updating what I want to change, is to make a new call to the database first, setting all of the required information for a Model (or whatever you are using to store your data) to what is currently in the DB. Then making the necessary changes to that information, and then saving the result to the DB.

You can look at the tutorial on Implementing Basic CRUD here for more information: http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/implementing-basic-crud-functionality-with-the-entity-framework-in-asp-net-mvc-application

pinmonkeyiii
  • 191
  • 1
  • 3
0

Please look at my Update method on the following question: Partially updating object with EF Code First and ASP.NET MVC This works nice, even when I dislike, that I have to specify the field names.

Community
  • 1
  • 1
Net User HH
  • 213
  • 2
  • 10