Coder Perfect

Updating a Record in Entity Framework 5

Problem

I’ve been looking into several ways to edit/update a record using Entity Framework 5 in an ASP.NET MVC3 environment, but none of them seem to check all of the requirements. I’ll tell you why.

I’ve discovered three approaches for which I’ll discuss the benefits and drawbacks:

Method 1: Load the original record and make changes to each property.

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    original.BusinessEntityId = updatedUser.BusinessEntityId;
    original.Email = updatedUser.Email;
    original.EmployeeId = updatedUser.EmployeeId;
    original.Forename = updatedUser.Forename;
    original.Surname = updatedUser.Surname;
    original.Telephone = updatedUser.Telephone;
    original.Title = updatedUser.Title;
    original.Fax = updatedUser.Fax;
    original.ASPNetUserId = updatedUser.ASPNetUserId;
    db.SaveChanges();
}    

Pros

Cons

Method 2: Load the original record and update the values.

var original = db.Users.Find(updatedUser.UserId);

if (original != null)
{
    db.Entry(original).CurrentValues.SetValues(updatedUser);
    db.SaveChanges();
}

Pros

Cons

Method 3: Attach the updated record to EntityState and change the state. Modified

db.Users.Attach(updatedUser);
db.Entry(updatedUser).State = EntityState.Modified;
db.SaveChanges();

Pros

Cons

Question

I have a question for you guys: is there a clear approach for me to fulfill this set of objectives?

I realize this is a trivial concern to make, but I believe I am overlooking a simple remedy. If approach one fails, method two will win;-)

Asked by Stokedout

Solution #1

What you’re looking for is:

db.Users.Attach(updatedUser);
var entry = db.Entry(updatedUser);
entry.Property(e => e.Email).IsModified = true;
// other changed properties
db.SaveChanges();

Answered by Ladislav Mrnka

Solution #2

The accepted response appeals to me greatly. I suppose there is yet another way to go about this. Let’s imagine you have a small set of properties that you never wish to include in a View, therefore those are excluded while updating the entity. Let’s imagine the two fields are Password and Social Security Number.

db.Users.Attach(updatedUser);

var entry = db.Entry(updatedUser);
entry.State = EntityState.Modified;

entry.Property(e => e.Password).IsModified = false;
entry.Property(e => e.SSN).IsModified = false;   

db.SaveChanges();   

After adding a new field to your Users table and View, this example allows you to essentially leave your business logic alone.

Answered by smd

Solution #3

foreach(PropertyInfo propertyInfo in original.GetType().GetProperties()) {
    if (propertyInfo.GetValue(updatedUser, null) == null)
        propertyInfo.SetValue(updatedUser, propertyInfo.GetValue(original, null), null);
}
db.Entry(original).CurrentValues.SetValues(updatedUser);
db.SaveChanges();

Answered by Stefano Camisassi

Solution #4

I have added an extra update method onto my repository base class that’s similar to the update method generated by Scaffolding. It sets a group of individual properties rather than the entire object to “changed.” (T is a class generic parameter.)

public void Update(T obj, params Expression<Func<T, object>>[] propertiesToUpdate)
{
    Context.Set<T>().Attach(obj);

    foreach (var p in propertiesToUpdate)
    {
        Context.Entry(obj).Property(p).IsModified = true;
    }
}

And then to call, for example:

public void UpdatePasswordAndEmail(long userId, string password, string email)
{
    var user = new User {UserId = userId, Password = password, Email = email};

    Update(user, u => u.Password, u => u.Email);

    Save();
}

One trip to the database is ideal for me. However, in order to prevent duplicating sets of characteristics, it’s usually better to do this with view models. I haven’t done it yet since I’m not sure how to keep the validation messages from my view model validators from showing up in my domain project.

Answered by Ian Warburton

Solution #5

public interface IRepository
{
    void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class;
}

public class Repository : DbContext, IRepository
{
    public void Update<T>(T obj, params Expression<Func<T, object>>[] propertiesToUpdate) where T : class
    {
        Set<T>().Attach(obj);
        propertiesToUpdate.ToList().ForEach(p => Entry(obj).Property(p).IsModified = true);
        SaveChanges();
    }
}

Answered by Matthew Steven Monkan

Post is based on https://stackoverflow.com/questions/15336248/entity-framework-5-updating-a-record