2012-12-31 74 views
6

我正在尝试使用附件使用EF 5.x进行更新。这个表格有其他必需的字段,但它是一个现有的行。所以我试图更新没有任何获取。用户标识是表的主键。我正在尝试更新状态。但它会抛出一个EntityValidationErrors说需要密码,这是另一个必填字段,但不是主键。因为这是对现有行的更新,为什么您需要提供需要更新的requried字段?附加更新实体框架

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); 
       } 
      } 
     } 
    } 
+0

您在第一行创建一个新的'webUser'并且不从数据库中获取一个。尝试设置一个断点,看看'webUser's'的密码是不是'null'。 – Yoav

+0

我并不想取数据。因为我打算做一个更新,我已经有一个主键 –

回答

1

在实体框架中,您无法为其他字段设置适当的值来更新字段。所以最好为你的工作使用存储过程。另一种方法是获取记录,然后更新字段。

+1

您可以设置dbxupdate.Configuration.ValidateOnSaveEnabled = false以禁用保存验证,如http://stackoverflow.com/a/33121240/2353894 – nhkhanh

+0

肮脏和最好的解决方案。尝试使用EF更新现有表时,您可能会遇到很多问题。 – Jacob

2

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

如果您在密码字段中有[Required]属性,我认为您很困难。您可能必须加载实体,然后更新信息而不是仅附加它。

+0

不,我没有那个数据属性。它需要在Db级但不是EF,我猜ADO.net从db中获取了这个属性。我没有看到生成的代码 –

+0

上的属性,它看起来像我必须创建一个SP来做到这一点。 –

+0

如果你只想更新记录的一部分而不首先加载整个实体,SP可能是一个好方法。 –

0

试试这个:替换第一行(这个地方的using语句中)
var wu = dbxupdate.webUsers.single(i=>i.id== webUserId);
wu.OnlineStatus = whatever;

代码继续...为了更新,你必须得到它的一个实例的实体。否则你正在创建一个新的未声明的属性值得到null值。

14

.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。也就是说,如果你有这样的:

foreach (var item in entityList) 
{ 
    var entity = db.Users.Single(a => a.id == item.id); 

    entity.Name = item.Name; 
    entity.Address = item.Address; 
} 

有人纠正我,如果我错了,但EF应该只更新实体/实际受此影响的代码字段。如果名称或地址保持不变,那么当它将更改保存到数据库时,EF将跳过该实体的该字段。