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