这是表格

用户

UserId
UserName
Password
EmailAddress

还有代码..

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

当前回答

我使用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还是它只是没有任何值。换句话说,属性值只能被替换为另一个值,而不能被清除。

其他回答

我用这个:

实体:

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

数据库上下文:

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

访问器代码:

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

你基本上有两个选择:

一直用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模型中为该存储过程创建一个函数导入,并且调用这个函数,而不是执行上面概述的步骤

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

Update Property是一个扩展方法

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

Update Wrapper是一个类

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

我使用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还是它只是没有任何值。换句话说,属性值只能被替换为另一个值,而不能被清除。

在寻找这个问题的解决方案时,我在Patrick Desjardins的博客上找到了GONeale的答案:

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

如你所见,它的第二个参数是a的表达式 函数。这将允许通过在Lambda中指定使用此方法 表示要更新哪个属性。”

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

(这里也给出了一个类似的解决方案:https://stackoverflow.com/a/5749469/2115384)

我目前在自己的代码中使用的方法,扩展到处理类型ExpressionType.Convert的(Linq)表达式。这在我的例子中是必要的,例如Guid和其他对象属性。它们被“包装”在Convert()中,因此没有被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();
}