这是表格
用户
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..
}
当前回答
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.
问题是Update方法中的第二个参数,
public int Update(T entity, Expression<Func<T, object>>[] properties).
使用提供的语法调用此方法…
Update(Model, d=>d.Name, d=>d.SecondProperty, d=>d.AndSoOn);
你必须在第二个参数前面加上'params'关键字。
public int Update(T entity, params Expression<Func<T, object>>[] properties)
或者如果你不想改变方法签名,那么要调用Update方法,你需要添加'new'关键字,指定数组的大小,然后最后使用集合对象初始化语法来更新每个属性,如下所示。
Update(Model, new Expression<Func<T, object>>[3] { d=>d.Name }, { d=>d.SecondProperty }, { d=>d.AndSoOn });
在@Doku-so的例子中,他指定了一个表达式数组,所以你必须在数组中传递属性来更新,因为数组你还必须指定数组的大小。为了避免这种情况,您还可以更改表达式参数,使用IEnumerable而不是数组。
下面是@Doku-so解决方案的实现。
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();
}
用法:
this.Update<Contact>(context, context.Entry(modifiedContact), c => c.Active, c => c.ContactTypeId);
@Doku-so提供了一种使用泛型的很酷的方法,我用这个概念来解决我的问题,但你不能使用@Doku-so的解决方案,在这篇文章和链接的帖子中,都没有人回答使用错误的问题。
其他回答
我用这个:
实体:
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();
Ladislav的答案更新为使用DbContext(在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();
}
}
_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; }
}
虽然我已经晚了,但这就是我所做的,我花了一段时间去寻找一个让我满意的解决方法;当你通过“白名单”概念显式地定义它们是什么时,这只会为更改的字段生成一个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。