这是表格

用户

UserId
UserName
Password
EmailAddress

还有代码..

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

当前回答

结合几项建议,我提出如下:

    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;
        } 
    }

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

或通过

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

或通过

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

其他回答

虽然我已经晚了,但这就是我所做的,我花了一段时间去寻找一个让我满意的解决方法;当你通过“白名单”概念显式地定义它们是什么时,这只会为更改的字段生成一个UPDATE语句,这更安全,可以防止web表单注入。

摘自我的ISession数据存储库:

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;
}

如果您愿意,可以将其封装在try. catch中,但我个人希望调用者了解此场景中的例外情况。

它将以类似这样的方式被调用(对我来说,这是通过ASP。NET Web API):

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

在EntityFramework Core 2中。x不需要附加:

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

尝试在SQL Server和分析它:

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确保已经加载的实体不会触发SELECT,并在需要时自动附加实体(来自文档):

查找具有给定主键值的实体。如果上下文正在跟踪具有给定主键值的实体,则立即返回该实体,而无需向数据库发出请求。否则,将向数据库查询具有给定主键值的实体,如果找到该实体,则将该实体附加到上下文并返回。如果没有找到实体,则返回null。

你基本上有两个选择:

一直用EF的方法,在这种情况下,你会 根据提供的userId加载对象——整个对象都会被加载 更新密码字段 使用上下文的.SaveChanges()方法将对象保存回来

在这种情况下,具体如何处理就取决于EF了。我刚刚测试了这个,在这种情况下,我只改变一个对象的一个字段,EF创建的几乎是你手动创建的,太像:

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

因此,EF足够聪明,可以找出哪些列确实发生了更改,并且它将创建一个T-SQL语句来处理实际上必要的更新。

你在T-SQL代码中定义了一个完全满足你需要的存储过程(只更新给定UserId的Password列,其他什么都不做——基本上执行update dbo。Users SET Password = @Password WHERE UserId = @UserId),然后在EF模型中为该存储过程创建一个函数导入,并且调用这个函数,而不是执行上面概述的步骤

我使用valueinjector nuget注入绑定模型到数据库实体使用如下:

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();
}

注意使用自定义约定,如果属性在服务器上为空,则不更新属性。

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);
    }
}

用法:

target.InjectFrom<NoNullsInjection>(source);

值注入器V2

查找这个答案

警告

您将不知道该属性是被故意清除为null还是它只是没有任何值。换句话说,属性值只能被替换为另一个值,而不能被清除。

您可以告诉EF哪些属性必须以这种方式更新:

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();
  }
}