【问题标题】:Entity Framework Update Problem实体框架更新问题
【发布时间】:2011-10-21 15:16:24
【问题描述】:

我正在使用实体框架和 LINQ 来检索数据。我遇到以下问题:

var customer= db.customers.where(c=>c.id==1);
customer.name=santhosh;
customer.city=hyd;

在我调用之前,数据库中的字段正在发生变化:

db.SaveChanges();

如何避免这种情况?

【问题讨论】:

  • 您的意思是其他人可以从应用程序的不同实例更新数据库中的字段吗?还是您的意思是即使不调用 SaveChanges 更改值似乎也会更改数据库行?
  • 您的 DbContext 是否存储在静态变量中?
  • 你不能提供你真正使用的代码吗?您显示的代码甚至无法编译。不可编译的代码不能改变数据库中的任何东西。

标签: c# .net entity-framework linq-to-entities


【解决方案1】:

正如其他人所说,我相信您也在其他地方使用您的上下文,并且其他位置正在调用 savechanges 并更新所有内容。尝试使用 using 语句执行 @Evan 建议的操作,以确保您有新的上下文。

AsNoTracking 不会确保您获得未缓存在数据库中的实体,其目的是不将对象放入上下文中。如果您使用 AsNoTracking,然后更改查询中返回的实体,则需要在调用 savechanges 之前将它们按修改后的形式附加到上下文中,否则它们将不会被更新。

    var customer= db.customers.AsNoTracking().Single(c=>c.id==1);
    customer.name=santhosh;
    customer.city=hyd;
    ctx.customers.Attach(customer);

    ctx.ObjectStateManager.ChangeObjectState(customer, System.Data.EntityState.Modified);

我本来只是对其他帖子发表评论,但还没有足够的代表。

【讨论】:

    【解决方案2】:

    检查您是否将 db 对象传递给其他方法,并在那里调用 SaveChanges()?

    或者检查您是否有异常的 catch 块,并且您可能在 catch 块中使用 SaveChanges() 来记录错误消息?

    (这些是常见的编程错误)

    【讨论】:

      【解决方案3】:

      在我调用之前,数据库中的字段正在更改

      如果您的意思是在应用程序外部进行更改,例如在 SQL Management Studio 中进行更改。 Entity Framework 无法检测到这些更改,因此您可能会得到 Entity Framework 缓存的陈旧对象。要防止接收缓存对象并从数据库中获取最新值,请使用 AsNoTracking。

      试试把 AsNoTracking():

      var customer= db.customers.AsNoTracking().where(c=>c.id==1);
      customer.name=santhosh;
      customer.city=hyd;
      db.SaveChanges();
      

      或者,如果您的问题是检测同一行的并发更新(unfortunate terminology,它不适用于 UPDATE),请使用 rowversion(又名时间戳)字段类型;然后在您的 .NET 代码上在属性上添加 Timestamp 属性。示例:http://www.ienablemuch.com/2011/07/entity-framework-concurrency-checking.html

      public class Song
      {
          [Key]
          public int SongId { get; set; }
          public string SongName { get; set; }
          public string AlbumName { get; set; }
      
          [Timestamp]
          public virtual byte[] Version { get; set; }
      }
      

      更新(在您发表评论后)

      如果您真的不打算将对象更改持久化到数据库中。尝试分离对象。

      试试这个:

      var customer= db.customers.where(c=>c.id==1);
      db.Entry(customer).State = System.Data.EntityState.Detached; // add this
      customer.name=santhosh;
      customer.city=hyd;    
      db.SaveChanges();
      

      这不会将您对名称和城市的更改保存到数据库中。

      如果你想要更健壮的东西(如果对象尚未附加,上述将失败异常),创建一个帮助器:

      private static void Evict(DbContext ctx, Type t, 
          string primaryKeyName, object id)
      {            
          var cachedEnt =
              ctx.ChangeTracker.Entries().Where(x =>   
                  ObjectContext.GetObjectType(x.Entity.GetType()) == t)
                  .SingleOrDefault(x =>
              {
                  Type entType = x.Entity.GetType();
                  object value = entType.InvokeMember(primaryKeyName, 
                                      System.Reflection.BindingFlags.GetProperty, 
                                      null, x.Entity, new object[] { });
       
                  return value.Equals(id);
              });
       
          if (cachedEnt != null)
              ctx.Entry(cachedEnt.Entity).State = EntityState.Detached;
      }
      

      使用:Evict(yourDbContextHere, typeof(Product), "ProductId", 1);

      http://www.ienablemuch.com/2011/08/entity-frameworks-nhibernate.html

      【讨论】:

      • 我的意思是即使不调用 SaveChanges,更改值似乎也会改变数据库行?
      • 这很奇怪,您是否尝试过在一个简单的程序中重现该问题?或控制台。查看问题是否可重现
      【解决方案4】:

      你能多提供一点周围的代码吗?如果不了解您是如何构建上下文的,可能会有点困难。

      这是我通常处理更新的方式(我希望它可以提供一些见解):

             using (var ctx = new myModel.myEntities())
              {
                  int pollID = 1;
                  var poll = (from p in ctx.Polls
                              where p.PollID == pollID
                              select p).FirstOrDefault();
      
                  poll.Question = txtPoll.Text.Trim();
                  ctx.SaveChanges();
              }
      

      【讨论】:

      • 说对于上面的例子,使用 (var ctx = new myModel.myEntities()) { int pollID = 1; var poll = (from p in ctx.Polls where p.PollID == pollID select p).FirstOrDefault(); poll.Question = txtPoll.Text.Trim(); /// 甚至在我调用 ctx.SaveChanges();这些值 poll.Question,正在数据库中更新
      • @santhosh - 您能否创建一个示例项目来复制此问题并将其上传到某处。
      【解决方案5】:

      杰克伍德沃德,你的不适合我。

      我不得不为 SQL Compact 稍作改动。

      var customer= db.customers.AsNoTracking().Single(c=>c.id==1);     
      
      db.customers.Attach(customer);      
      customer.name=santhosh;     
      customer.city=hyd;     
      db.ObjectStateManager.ChangeObjectState(customer, System.Data.EntityState.Modified); 
      db.SaveChanges();
      
      db.Dispose();
      

      这样效果更好。

      【讨论】:

        猜你喜欢
        • 2015-01-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-10-25
        • 2015-10-30
        • 1970-01-01
        相关资源
        最近更新 更多