附加更新实体框架

本文关键字:框架 实体 更新 | 更新日期: 2023-09-27 17:50:29

我正在尝试使用EF 5对表进行更新。X使用attach。这个表有其他必需的字段,但它是一个现有的行。我尝试在不取回的情况下进行更新。Userid是表的主键。我正在尝试更新状态。但它会抛出EntityValidationErrors,说密码是必需的,这是另一个必需字段,但不是主键。既然这是对现有行的更新,为什么需要提供更新所需的字段?

    var webUser = new WebUser() { UserId = webUserId, OnlineStatus = (sbyte)status };
    using (var dbxupdate = new xEntities())
    {
        try
        {
            dbxupdate.WebUsers.Attach(webUser);
dbxupdate.Entry(webUser).State = EntityState.Modified;
            dbxupdate.Entry(webUser).Property(x => x.OnlineStatus).IsModified = true;
            dbxupdate.SaveChanges();
        }
        catch (DbEntityValidationException dbEx)
        {
            foreach (var validationErrors in dbEx.EntityValidationErrors)
            {
                foreach (var validationError in validationErrors.ValidationErrors)
                {
                    Trace.TraceInformation("Property: {0} Error: {1}", validationError.PropertyName, validationError.ErrorMessage);
                }
            }
        }
    }

附加更新实体框架

.Attach()实际上只用于在分离场景中更新实体,如:

User entity = null;
using (var db = new DbContext()) {
    entity = (from p in db.Users
              where p.Id == 1
              select p).FirstOrDefault();
    System.Diagnostics.Trace.WriteLine(entity.Name); //Outputs "Jane Doe"
}
entity.Name = "John Doe" //Modified while no longer connected to database
using (var db = new DbContext()) {
    db.Users.Attach(entity);
    db.Entry(entity).Property(a => a.Name).IsModified = true;
    db.SaveChanges();
    System.Diagnostics.Trace.WriteLine(entity.Name); //Now outputs "John Doe"
}

在您的场景中,您创建的实体没有通过其键被检索,数据库将其视为一个全新的实体。我假设您的密码是一个非空字段,这会导致EF在尝试保存您的更改时抛出错误。如果你没有任何这样的错误,那么EF会自动清空你没有修改的任何字段,然后保存实体(这也不是你想要的结果)。

为了做出你真正想要的改变,试着这样做:

using (var db = new DbContext()) {
    db.Users
        .Single(a => (a.Id == 1))
        .OnlineStatus = ((sbyte)status);
    db.SaveChanges();
}

然后添加您想要的任何其他错误处理/验证代码。或者,您可以将实体存储在变量中,以便一次对多个字段进行更改。EF应该自动确定哪些值被更改了,并且只生成进行这些更改所需的SQL。意思是如果你有这样的东西:

using (var db = new DbContext()) {
    foreach (var item in entityList) {
        var entity = db.Users.Single(a => (a.Id == item.Id));
        entity.Name = item.Name;
        entity.Address = item.Address;
    }
    db.SaveChanges();
}

则EF应该只更新实际受此代码影响的实体/字段。如果Name或Address保持不变,那么EF在将更改保存到数据库时将跳过该实体的该字段。

实体在保存时进行验证,无论它是附加的还是从数据库加载的。如果使用验证属性或验证方法,实体必须通过验证才能保存。

如果您在密码字段上有[Required]属性,我认为您非常卡住。你可能需要加载实体,然后更新信息,而不是仅仅附加它。

在实体框架中,如果不为其他字段设置适当的值,则无法更新字段。因此,最好为您的作业使用存储过程。另一种方法是获取记录然后更新字段

试着这样做:将第一行替换为(将其放在using语句中)
var wu = dbxupdate.webUsers.single(i=>i.id== webUserId);
wu.OnlineStatus = whatever;

代码还在继续……为了更新一个实体,你必须获得它的一个实例。否则,您将创建一个新属性,其中未声明的属性将获得null值。