如何使用Entity Framework仅更新一个字段?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何使用Entity Framework仅更新一个字段?相关的知识,希望对你有一定的参考价值。

这是桌子

用户

UserId
UserName
Password
EmailAddress

和代码..

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

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();
  }
}
另一答案

在EntityFramework Core 2.x中,不需要Attach

 // 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

查找确保已加载的实体不会触发SELECT,并在需要时自动附加实体(来自文档):

    ///     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.
另一答案

我使用ValueInjecter nuget将Binding Model注入数据库Entity,使用以下命令:

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

请注意自定义约定的使用,如果它们从服务器返回null,则不会更新属性。

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

查找this answer

警告

您不会知道该属性是否被故意清除为空或它只是没有任何值。换句话说,属性值只能替换为其他值但不能清除。

另一答案

我一直在寻找,最后我找到了解决方案

using (CString conn = new CString())
{
    USER user = conn.USERs.Find(CMN.CurrentUser.ID);
    user.PASSWORD = txtPass.Text;
    conn.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;
另一答案
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;
    }
}
另一答案
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();
  }
}
另一答案

您可以告诉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();
  }
}
另一答案

你基本上有两个选择:

  • 一路走EF方式,在这种情况下,你会的 根据提供的userId加载对象 - 整个对象被加载 更新password字段 使用上下文的.SaveChanges()方法保存对象

在这种情况下,由EF如何详细处理。我只测试了这个,在这种情况下我只更改一个对象的单个字段,EF创建的几乎就是你手动创建的东西 - 例如:

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

因此,EF非常聪明,可以确定哪些列确实已更改,并且它将创建一个T-SQL语句来处理实际上必要的更新。

  • 你可以在T-SQL代码中定义一个完全符合你需要的存储过程(只需更新给定PasswordUserId列,而不是其他任何内容 - 基本上执行UPDATE dbo.Users SET Password = @Password WHERE UserId = @UserId),然后在EF模型中为该存储过程创建一个函数导入。您调用此函数而不是执行上述步骤
另一答案

我正在使用这个:

实体:

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

访问代码:

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();
另一答案

在寻找这个问题的解决方案时,我通过Patrick Desjardins' blog找到了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();
}

“正如您所看到的,它将第二个参数作为函数的表达式。这将通过在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.GetExpression

以上是关于如何使用Entity Framework仅更新一个字段?的主要内容,如果未能解决你的问题,请参考以下文章

C# Entity Framework Code-First-如何仅使用该外键的 id 添加带有外键的行?

Entity Framework使用EntityState和Attach来保存数据变化以及更新实体的个别字段

使用 Entity Framework 仅计算值的 LINQ 查询

在服务器中使用 Entity Framework 的 Migration 更新数据库

entity framework Code First 中,对有主外键关联数据怎么更新

向数据库添加新表后如何更新 Entity Framework Core