How to update only one field using Entity Framework?

SqlEntity Framework-4EntityFieldDbcontext

Sql Problem Overview


Here's the table

Users

UserId
UserName
Password
EmailAddress

and the code..

public void ChangePassword(int userId, string password){
//code to update the password..
}

Sql Solutions


Solution 1 - Sql

Ladislav's answer updated to use DbContext (introduced in EF 4.1):

public void ChangePassword(int userId, string password)
{
    var user = new User() { Id = userId, Password = password };
    using (var db = new MyEfContextName())
    {
        db.Users.Attach(user);
        db.Entry(user).Property(x => x.Password).IsModified = true;
        db.SaveChanges();
    }
}

Solution 2 - Sql

You can tell EF which properties have to be updated in this way:

public void ChangePassword(int userId, string password)
{
  var user = new User { Id = userId, Password = password };
  using (var context = new ObjectContext(ConnectionString))
  {
    var users = context.CreateObjectSet<User>();
    users.Attach(user);
    context.ObjectStateManager.GetObjectStateEntry(user)
      .SetModifiedProperty("Password");
    context.SaveChanges();
  }
}

Solution 3 - Sql

In Entity Framework Core, Attach returns the entry, so all you need is:

var user = new User { Id = userId, Password = password };
db.Users.Attach(user).Property(x => x.Password).IsModified = true;
db.SaveChanges();

Solution 4 - Sql

You have basically two options:

  • go the EF way all the way, in that case, you would
  • load the object based on the userId provided - the entire object gets loaded
  • update the password field
  • save the object back using the context's .SaveChanges() method

In this case, it's up to EF how to handle this in detail. I just tested this, and in the case I only change a single field of an object, what EF creates is pretty much what you'd create manually, too - something like:

`UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId`

So EF is smart enough to figure out what columns have indeed changed, and it will create a T-SQL statement to handle just those updates that are in fact necessary.

  • you define a stored procedure that does exactly what you need, in T-SQL code (just update the Password column for the given UserId and nothing else - basically executes UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId) and you create a function import for that stored procedure in your EF model and you call this function instead of doing the steps outlined above

Solution 5 - Sql

i'm using this:

entity:

public class Thing 
{
    [Key]
    public int Id { get; set; }
    public string Info { get; set; }
    public string OtherStuff { get; set; }
}

dbcontext:

public class MyDataContext : DbContext
{
    public DbSet<Thing > Things { get; set; }
}

accessor code:

MyDataContext ctx = new MyDataContext();

// FIRST create a blank object
Thing thing = ctx.Things.Create();

// SECOND set the ID
thing.Id = id;

// THIRD attach the thing (id is not marked as modified)
db.Things.Attach(thing); 

// FOURTH set the fields you want updated.
thing.OtherStuff = "only want this field updated.";

// FIFTH save that thing
db.SaveChanges();

Solution 6 - Sql

While searching for a solution to this problem, I found a variation on GONeale's answer through Patrick Desjardins' blog:

public int Update(T entity, Expression<Func<T, object>>[] properties)
{
  DatabaseContext.Entry(entity).State = EntityState.Unchanged;
  foreach (var property in properties)
  {
    var propertyName = ExpressionHelper.GetExpressionText(property);
    DatabaseContext.Entry(entity).Property(propertyName).IsModified = true;
  }
  return DatabaseContext.SaveChangesWithoutValidation();
}

> "As you can see, it takes as its second parameter an expression of a > function. This will let use this method by specifying in a Lambda > expression which property to update."

...Update(Model, d=>d.Name);
//or
...Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);

( A somewhat similar solution is also given here: https://stackoverflow.com/a/5749469/2115384 )

The method I am currently using in my own code, extended to handle also (Linq) Expressions of type ExpressionType.Convert. This was necessary in my case, for example with Guid and other object properties. Those were 'wrapped' in a Convert() and therefore not handled by System.Web.Mvc.ExpressionHelper.GetExpressionText.

public int Update(T entity, Expression<Func<T, object>>[] properties)
{
	DbEntityEntry<T> entry = dataContext.Entry(entity);
	entry.State = EntityState.Unchanged;
	foreach (var property in properties)
	{
		string propertyName = "";
		Expression bodyExpression = property.Body;
		if (bodyExpression.NodeType == ExpressionType.Convert && bodyExpression is UnaryExpression)
		{
			Expression operand = ((UnaryExpression)property.Body).Operand;
			propertyName = ((MemberExpression)operand).Member.Name;
		}
		else
		{
			propertyName = System.Web.Mvc.ExpressionHelper.GetExpressionText(property);
		}
		entry.Property(propertyName).IsModified = true;
	}

	dataContext.Configuration.ValidateOnSaveEnabled = false;
	return dataContext.SaveChanges();
}

Solution 7 - Sql

In EntityFramework Core 2.x there is no need for Attach:

 // get a tracked entity
 var entity = context.User.Find(userId);
 entity.someProp = someValue;
 // other property changes might come here
 context.SaveChanges();

Tried this in SQL Server and profiling it:

exec sp_executesql N'SET NOCOUNT ON;
UPDATE [User] SET [someProp] = @p0
WHERE [UserId] = @p1;
SELECT @@ROWCOUNT;

',N'@p1 int,@p0 bit',@p1=1223424,@p0=1

Find ensures that already loaded entities do not trigger a SELECT and also automatically attaches the entity if needed (from the docs):

    ///     Finds an entity with the given primary key values. If an entity with the given primary key values
    ///     is being tracked by the context, then it is returned immediately without making a request to the
    ///     database. Otherwise, a query is made to the database for an entity with the given primary key values
    ///     and this entity, if found, is attached to the context and returned. If no entity is found, then
    ///     null is returned.

Solution 8 - Sql

I'm late to the game here, but this is how I am doing it, I spent a while hunting for a solution I was satisified with; this produces an UPDATE statement ONLY for the fields that are changed, as you explicitly define what they are through a "white list" concept which is more secure to prevent web form injection anyway.

An excerpt from my ISession data repository:

public bool Update<T>(T item, params string[] changedPropertyNames) where T 
  : class, new()
{
    _context.Set<T>().Attach(item);
    foreach (var propertyName in changedPropertyNames)
    {
        // If we can't find the property, this line wil throw an exception, 
        //which is good as we want to know about it
        _context.Entry(item).Property(propertyName).IsModified = true;
    }
    return true;
}

This could be wrapped in a try..catch if you so wished, but I personally like my caller to know about the exceptions in this scenario.

It would be called in something like this fashion (for me, this was via an ASP.NET Web API):

if (!session.Update(franchiseViewModel.Franchise, new[]
    {
      "Name",
      "StartDate"
  }))
  throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));

Solution 9 - Sql

Entity framework tracks your changes on objects that you queried from database via DbContext. For example if you DbContext instance name is dbContext

public void ChangePassword(int userId, string password){
     var user = dbContext.Users.FirstOrDefault(u=>u.UserId == userId);
     user.password = password;
     dbContext.SaveChanges();
}

Solution 10 - Sql

I know this is an old thread but I was also looking for a similar solution and decided to go with the solution @Doku-so provided. I'm commenting to answer the question asked by @Imran Rizvi , I followed @Doku-so link that shows a similar implementation. @Imran Rizvi's question was that he was getting an error using the provided solution 'Cannot convert Lambda expression to Type 'Expression> [] ' because it is not a delegate type'. I wanted to offer a small modification I made to @Doku-so's solution that fixes this error in case anyone else comes across this post and decides to use @Doku-so's solution.

The issue is the second argument in the Update method,

public int Update(T entity, Expression<Func<T, object>>[] properties). 

To call this method using the syntax provided...

Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn); 

You must add the 'params' keyword in front of the second arugment as so.

public int Update(T entity, params Expression<Func<T, object>>[] properties)

or if you don't want to change the method signature then to call the Update method you need to add the 'new' keyword, specify the size of the array, then finally use the collection object initializer syntax for each property to update as seen below.

Update(Model, new Expression<Func<T, object>>[3] { d=>d.Name }, { d=>d.SecondProperty }, { d=>d.AndSoOn });

In @Doku-so's example he is specifying an array of Expressions so you must pass the properties to update in an array, because of the array you must also specify the size of the array. To avoid this you could also change the expression argument to use IEnumerable instead of an array.

Here is my implementation of @Doku-so's solution.

public int Update<TEntity>(LcmsEntities dataContext, DbEntityEntry<TEntity> entityEntry, params Expression<Func<TEntity, object>>[] properties)
     where TEntity: class
    {
        entityEntry.State = System.Data.Entity.EntityState.Unchanged;

        properties.ToList()
            .ForEach((property) =>
            {
                var propertyName = string.Empty;
                var bodyExpression = property.Body;
                if (bodyExpression.NodeType == ExpressionType.Convert
                    && bodyExpression is UnaryExpression)
                {
                    Expression operand = ((UnaryExpression)property.Body).Operand;
                    propertyName = ((MemberExpression)operand).Member.Name;
                }
                else
                {
                    propertyName = System.Web.Mvc.ExpressionHelper.GetExpressionText(property);
                }

                entityEntry.Property(propertyName).IsModified = true;
            });

        dataContext.Configuration.ValidateOnSaveEnabled = false;

        return dataContext.SaveChanges();
    }

Usage:

this.Update<Contact>(context, context.Entry(modifiedContact), c => c.Active, c => c.ContactTypeId);
 

@Doku-so provided a cool approach using generic's, I used the concept to solve my issue but you just can't use @Doku-so's solution as is and in both this post and the linked post no one answered the usage error questions.

Solution 11 - Sql

Combining several suggestions I propose the following:

    async Task<bool> UpdateDbEntryAsync<T>(T entity, params Expression<Func<T, object>>[] properties) where T : class
    {
        try
        {
            var entry = db.Entry(entity);
            db.Set<T>().Attach(entity);
            foreach (var property in properties)
                entry.Property(property).IsModified = true;
            await db.SaveChangesAsync();
            return true;
        }
        catch (Exception ex)
        {
            System.Diagnostics.Debug.WriteLine("UpdateDbEntryAsync exception: " + ex.Message);
            return false;
        } 
    }

called by

UpdateDbEntryAsync(dbc, d => d.Property1);//, d => d.Property2, d => d.Property3, etc. etc.);

Or by

await UpdateDbEntryAsync(dbc, d => d.Property1);

Or by

bool b = UpdateDbEntryAsync(dbc, d => d.Property1).Result;

Solution 12 - Sql

I use ValueInjecter nuget to inject Binding Model into database Entity using following:

public async Task<IHttpActionResult> Add(CustomBindingModel model)
{
   var entity= await db.MyEntities.FindAsync(model.Id);
   if (entity== null) return NotFound();

   entity.InjectFrom<NoNullsInjection>(model);

   await db.SaveChangesAsync();
   return Ok();
}

Notice the usage of custom convention that doesn't update Properties if they're null from server.

ValueInjecter v3+

public class NoNullsInjection : LoopInjection
{
    protected override void SetValue(object source, object target, PropertyInfo sp, PropertyInfo tp)
    {
        if (sp.GetValue(source) == null) return;
        base.SetValue(source, target, sp, tp);
    }
}

Usage:

target.InjectFrom<NoNullsInjection>(source);

Value Injecter V2

Lookup this answer

Caveat

You won't know whether the property is intentionally cleared to null OR it just didn't have any value it. In other words, the property value can only be replaced with another value but not cleared.

Solution 13 - Sql

I was looking for same and finally I found the solution

using (CString conn = new CString())
{
    USER user = conn.USERs.Find(CMN.CurrentUser.ID);
    user.PASSWORD = txtPass.Text;
    conn.SaveChanges();
}

believe me it work for me like a charm.

Solution 14 - Sql

_context.Users.UpdateProperty(p => p.Id, request.UserId, new UpdateWrapper<User>()
                {
                    Expression = p => p.FcmId,Value = request.FcmId
                });
   await _context.SaveChangesAsync(cancellationToken);

Update Property is an extension method

public static void UpdateProperty<T, T2>(this DbSet<T> set, Expression<Func<T, T2>> idExpression,
            T2 idValue,
            params UpdateWrapper<T>[] updateValues)
            where T : class, new()
        {
            var entity = new T();
            var attach = set.Attach(entity);
            attach.Property(idExpression).IsModified = false;
            attach.Property(idExpression).OriginalValue = idValue;
            foreach (var update in updateValues)
            {
                attach.Property(update.Expression).IsModified = true;
                attach.Property(update.Expression).CurrentValue = update.Value;
            }
        }

And Update Wrapper is a class

public class UpdateWrapper<T>
    {
        public Expression<Func<T, object>> Expression  { get; set; }
        public object Value { get; set; }
    }

Solution 15 - Sql

public async Task<bool> UpdateDbEntryAsync(TEntity entity, params Expression<Func<TEntity, object>>[] properties)
{
    try
    {
        this.Context.Set<TEntity>().Attach(entity);
        EntityEntry<TEntity> entry = this.Context.Entry(entity);
        entry.State = EntityState.Modified;
        foreach (var property in properties)
            entry.Property(property).IsModified = true;
        await this.Context.SaveChangesAsync();
        return true;
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

Solution 16 - Sql

public void ChangePassword(int userId, string password)
{
  var user = new User{ Id = userId, Password = password };
  using (var db = new DbContextName())
  {
    db.Entry(user).State = EntityState.Added;
    db.SaveChanges();
  }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questionh3nView Question on Stackoverflow
Solution 1 - SqlStuartView Answer on Stackoverflow
Solution 2 - SqlLadislav MrnkaView Answer on Stackoverflow
Solution 3 - SqlEdward BreyView Answer on Stackoverflow
Solution 4 - Sqlmarc_sView Answer on Stackoverflow
Solution 5 - SqlgroggyjavaView Answer on Stackoverflow
Solution 6 - SqlDoku-soView Answer on Stackoverflow
Solution 7 - SqlAlexei - check CodidactView Answer on Stackoverflow
Solution 8 - SqlGONealeView Answer on Stackoverflow
Solution 9 - SqlBahtiyar ÖzdereView Answer on Stackoverflow
Solution 10 - SqlPWSView Answer on Stackoverflow
Solution 11 - SqlGuyView Answer on Stackoverflow
Solution 12 - SqlKorayemView Answer on Stackoverflow
Solution 13 - SqlBurhan Ul Haqq ZahirView Answer on Stackoverflow
Solution 14 - SqlsupernerdView Answer on Stackoverflow
Solution 15 - Sqlpintu guptaView Answer on Stackoverflow
Solution 16 - SqlRahulView Answer on Stackoverflow