【问题标题】:Most efficient way to update with LINQ to SQL使用 LINQ to SQL 进行更新的最有效方法
【发布时间】:2011-02-21 18:39:06
【问题描述】:

我可以按照下面的函数更新我的员工记录,还是必须先查询员工集合然后更新数据?

  public int updateEmployee(App3_EMPLOYEE employee)
  {
      DBContextDataContext db = new DBContextDataContext();
      db.App3_EMPLOYEEs.Attach(employee);
      db.SubmitChanges();
      return employee.PKEY;
  }

或者我必须执行以下操作吗?

public int updateEmployee(App3_EMPLOYEE employee)
{
    DBContextDataContext db = new DBContextDataContext();
    App3_EMPLOYEE emp = db.App3_EMPLOYEEs.Single(e => e.PKEY == employee.PKEY);
    db.App3_EMPLOYEEs.Attach(employee,emp);
    db.SubmitChanges();
    return employee.PKEY;
}

但我不想使用第二个选项。有什么有效的方法来更新数据吗?

我在使用这两种方法时都遇到了这个错误:

已尝试附加或添加一个不是新的实体,可能是从另一个 DataContext 加载的。这不受支持。

【问题讨论】:

  • 在第二种方法中,您将实体附加到上下文,因为它已经从中填充。只需调用 SubmitChanges()

标签: c# asp.net linq linq-to-sql datacontext


【解决方案1】:

使用此扩展方法更新所有属于列属性的属性:

public static void SaveToOriginal<T>(this T original, T actual)
    {
        foreach (var prop in typeof(T).GetProperties(BindingFlags.Public | BindingFlags.Instance)
            .Where(info => info.GetCustomAttribute<System.Data.Linq.Mapping.ColumnAttribute>() != null))
        {
            prop.SetValue(original, prop.GetValue(actual));
        }
    }

我的意思是,首先你从数据库中恢复原件,使用该方法将所有列属性从新元素映射到原件,最后提交。 我希望这会有所帮助。

【讨论】:

    【解决方案2】:

    这是我的 Repository 类中的一个函数,用于更新实体

    protected void Attach(TEntity entity)
    {
       try
        {
           _dataContext.GetTable<TEntity>().Attach(entity);
           _dataContext.Refresh(RefreshMode.KeepCurrentValues, entity);
        }
        catch (DuplicateKeyException ex) //Data context knows about this entity so just update values
        {
           _dataContext.Refresh(RefreshMode.KeepCurrentValues, entity);
        }
    }
    

    TEntity 是您的 DB 类,根据您的设置,您可能只想这样做

    _dataContext.Attach(entity);
    

    【讨论】:

      【解决方案3】:

      我找到了解决这个问题的方法:

      1) 获取和更新实体(我将使用这种方式,因为它对我来说没问题)

      public int updateEmployee(App3_EMPLOYEE employee)
      {
          AppEmployeeDataContext db = new AppEmployeeDataContext();
          App3_EMPLOYEE emp = db.App3_EMPLOYEEs.Single(e => e.PKEY == employee.PKEY);
          emp.FIRSTNAME = employee.FIRSTNAME;//copy property one by one 
          db.SubmitChanges();
          return employee.PKEY;
      }
      

      2) 如下禁用 ObjectTrackingEnabled

      // but in this case lazy loading is not supported
      
      
          public AppEmployeeDataContext() : 
                          base(global::LinqLibrary.Properties.Settings.Default.AppConnect3DBConnectionString, mappingSource)
                  {
                      this.ObjectTrackingEnabled = false;
                      OnCreated();
                  }
      

      3) 分离所有相关对象

      partial class App3_EMPLOYEE
      {
          public void Detach()
          {
              this._APP3_EMPLOYEE_EXTs = default(EntityRef<APP3_EMPLOYEE_EXT>);
          }
      }
      
       public int updateEmployee(App3_EMPLOYEE employee)
      {
          AppEmployeeDataContext db = new AppEmployeeDataContext();
          employee.Detach();
          db.App3_EMPLOYEEs.Attach(employee,true);
          db.SubmitChanges();
          return employee.PKEY;
      }
      

      4) 在列中使用时间戳

       http://www.west-wind.com/weblog/posts/135659.aspx
      

      5) 创建用于更新数据的存储过程并通过数据库上下文调用它

      【讨论】:

        【解决方案4】:

        您可以使用此重载附加未附加的修改实体:

        db.App3_EMPLOYEEs.Attach(employee, true);//Attach as modfieied
        

        请注意,要使其正常工作,您需要在表格中添加“时间戳”类型的“版本”列

        【讨论】:

          【解决方案5】:

          有关于这个话题的讨论here at MSDN s 建议您使用 IsVersion 字段和 Attach 方法

          【讨论】:

            【解决方案6】:

            当没有 RowVersion 列时,您不能将修改的实体附加到 DataContext。相反,您可以将原始实体存储在您的应用程序中,只要维护数据更改的副本即可。然后,当需要保存更改时,您可以将原始实体附加到 DataContext,更改其值以匹配修改后的实体值并提交更改。

            这是一个例子:

            public int updateEmployee(App3_EMPLOYEE employee, App3_EMPLOYEE originalEmployee)
            {
                DBContextDataContext db = new DBContextDataContext();
                db.App3_EMPLOYEEs.Attach(originalEmployee);
            
                // TODO: Copy values from employee to original employee
            
                db.SubmitChanges();
                return employee.PKEY;
            }
            

            更新:

            数据库中有一个包含 ID、Name、Notes 列的表

            // fetch an employee which will not be changed in the application
            Employee original;
            using(var db = new TestDbDataContext())
            {
              original = db.Employees.First(e => e.ID == 2);
            }
            
            // create an instance to work with
            var modified = new Employee {ID = original.ID, Name = original.Name, Notes = original.Notes};
            
            // change some info
            modified.Notes = string.Format("new notes as of {0}", DateTime.Now.ToShortTimeString());  
            // update
            using(var db = new TestDbDataContext())
            {
              db.Employees.Attach(original);
              original.Notes = modified.Notes;
              db.SubmitChanges();
            }
            

            【讨论】:

            • 现在我正在使用相同的东西来处理修改为原始的数据
            • 所以这是我用来对数据库中记录的当前状态没有额外请求的方式。不同之处在于我将 original 实体附加到 DataContext,然后在提交之前修改附加的实体
            • 并且我认为您遇到的错误是因为在您的应用程序中的某个地方(您读取数据的地方)您没有处理数据上下文并且您的员工实体已附加到它。因此,如果您使用相同的数据上下文实例(用于检索)进行保存,那么它也应该适用于您。
            猜你喜欢
            • 2010-10-14
            • 1970-01-01
            • 2012-10-26
            • 1970-01-01
            • 1970-01-01
            • 2011-03-02
            • 1970-01-01
            • 2010-10-29
            • 1970-01-01
            相关资源
            最近更新 更多