Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MVC 5 Updating multiple fields of one row in database

I'm practicing MVC 5 and in my application I have a controller method that should update address info for a given user profile.

I do this by accessing the database with a context object, and my first thought was to copy the database row to an object, make the changes and then put it back using the AddOrUpdate() method. However, I only see an Add() method.

So instead I did the following:

public ActionResult EditBillingDetails(EditBillingDetailsViewModel model)
{
    if (ModelState.IsValid)
    {
        string id = User.Identity.GetUserId();
        ApplicationDbContext db = new ApplicationDbContext();

        db.Users.Single(u => u.Id == id).FirstName = model.FirstName;
        db.Users.Single(u => u.Id == id).LastName = model.LastName;
        db.Users.Single(u => u.Id == id).Email = model.Email;
        db.Users.Single(u => u.Id == id).Address = model.Address;
        db.Users.Single(u => u.Id == id).City = model.City;
        db.Users.Single(u => u.Id == id).ZIP = model.ZIP;
        db.Users.Single(u => u.Id == id).Country = model.Country;

        db.SaveChanges();

        return RedirectToAction("Manage", new { Message = ManageMessageId.ChangeBillingSuccess });
    }
    return View(model);
}

Which works just fine, but it feels wrong to go look up the same entry 7 times just to update each field one by one. Isn't there a better way to do this?

like image 288
Scopperloit Avatar asked Mar 19 '14 19:03

Scopperloit


3 Answers

The db.SaveChanges() will take care of updating an entity with new values if you retrieved it from the database. EF "tracks" entities that you query from the database (in this instance, the call to .Single()) and knows to persist changes back to the databse if you alter any properties of that entity. You only have to Add to the database if you are creating a completely new entity.

var user = db.Users.Single(u => u.Id == id);
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.Email = model.Email;
user.Address = model.Address;
user.City = model.City;
user.ZIP = model.ZIP;
user.Country = model.Country;

db.SaveChanges();
like image 190
Tommy Avatar answered Nov 19 '22 09:11

Tommy


Assuming this is Entity-Framekwork and you haven't changed any default configurations (caching), your code, although very specific, only the first Single() will make the database call to retrieve the object. So functionally it would be the same as:

var user = db.Users.Single(u => u.Id == id);
user.FirstName = model.FirstName;
user.LastName = model.LastName;
user.Email = model.Email;
user.Address = model.Address;
user.City = model.City;
user.ZIP = model.ZIP;
user.Country = model.Country;

db.SaveChanges();

There may be a additional (so minor) code execution depending on if the compiler would change your code in IL to the code I wrote.

like image 1
Erik Philips Avatar answered Nov 19 '22 09:11

Erik Philips


Why not get the user from the context?

public User GetUser(int id)
{
    DbContext context = new YourDbContext();
    return context.Users.Find(id);
}

public void SaveUser(User user)
{
    DbContext context = new YourDbContext();
    context.Entry(user).State = EntityState.Modified;
    context.SaveChanges();
    return;
}

In your Controller, you would update the User's properties and save it:

DbContext context = new YourDbContext();
User user = GetUser(User.Identity.GetUserId());
user.Value1 = model.Value1;
user.Value2 = model.Value2;
SaveUser(user);
return RedirectToAction(...);
like image 1
László Koller Avatar answered Nov 19 '22 08:11

László Koller