这是表格
用户
UserId
UserName
Password
EmailAddress
还有代码..
public void ChangePassword(int userId, string password){
//code to update the password..
}
这是表格
用户
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还是它只是没有任何值。换句话说,属性值只能被替换为另一个值,而不能被清除。
其他回答
你基本上有两个选择:
一直用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模型中为该存储过程创建一个函数导入,并且调用这个函数,而不是执行上面概述的步骤
虽然我已经晚了,但这就是我所做的,我花了一段时间去寻找一个让我满意的解决方法;当你通过“白名单”概念显式地定义它们是什么时,这只会为更改的字段生成一个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));
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;
}
}
在寻找这个问题的解决方案时,我在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();
}
结合几项建议,我提出如下:
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;