When you are a detached entity returns from the UI, you normally save the update like this:
public void UpdateMovie(Movie movie)
{
using (var context = new DomainContext())
{
//attach it
context.Movies.Attach(movie);
//mark it as modified
context.Entry(movie).State = EntityState.Modified;
//save - but saves all properties...
context.SaveChanges();
}
}The update property saves all the properties - but what if we only wanted to save certain properties? Like this:
update [dbo].[Movies]
set [BoxOffice] = @0
where ([Id] = @1)
The safest way is to do it manually (and you avoid mass assignment vulnerabilities). You have to reload the entity from the database.
public void UpdateMovieBoxOffice(Movie movie)
{
using (var context = new DomainContext())
{
//get database version
var databaseMovie = context.Movies.Find(movie.Id);
//manually copy the values
databaseMovie.BoxOffice = movie.BoxOffice;
//save
context.SaveChanges();
}
}The UI may be able to track changes (IPropertyNotifyChanged or similar) and give the data service a list of the changed properties. If so, we can use the context.Entry to specify the modified properties. The SQL UPDATE statement will update only those properties.
public void UpdateMovieProperties(Movie movie, IList<string> propertyNames)
{
using (var context = new DomainContext())
{
//attach it
context.Movies.Attach(movie);
//use the context entry
DbEntityEntry<Movie> entry = context.Entry(movie);
foreach (var propertyName in propertyNames)
{
//modify the specific property states only
entry.Property(propertyName).IsModified = true;
}
//save
context.SaveChanges();
}
}
The other way is to detect the changes by comparing them to the database. This is similar to the second method, but we use entry.GetDatabaseValues() to get the database values and then compare them. As only the changed properties are marked as modified, the UPDATE statement uses only those properties.
public void UpdateMovieChangedProperties(Movie movie)
{
using (var context = new DomainContext())
{
//attach it
context.Movies.Attach(movie);
//use the context entry
DbEntityEntry<Movie> entry = context.Entry(movie);
//do a database call to get the state
var databaseValues = entry.GetDatabaseValues();
foreach (var propertyName in databaseValues.PropertyNames)
{
//modify the specific property states only
entry.Property(propertyName).IsModified = true;
}
//save
context.SaveChanges();
}
}We don't take account of Complex Properties here (the DbPropertyEntries can be nested).