Самый эффективный способ обновления с помощью LINQ to SQL - PullRequest
22 голосов
/ 20 мая 2010

Могу ли я обновить свою запись о сотруднике, как указано в функции ниже, или мне нужно сначала сделать запрос о коллекции сотрудников, а затем обновить данные?

  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. Это не поддерживается.

Ответы [ 6 ]

9 голосов
/ 20 мая 2010

Я нашел следующие решения этой проблемы:

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) Создайте хранимую процедуру для обновления ваших данных и вызовите ее по контексту БД

3 голосов
/ 01 июня 2010

Вы не можете присоединить измененный объект к DataContext, когда столбец RowVersion отсутствует. Вместо этого вы можете хранить исходную сущность в вашем приложении до тех пор, пока сохраняете копию для изменений данных. Затем, когда необходимо сохранить изменения, вы можете присоединить исходный объект к 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;
}

Обновление:

В базе данных есть таблица с идентификаторами столбцов, именем, примечаниями

// 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();
}
2 голосов
/ 11 декабря 2012

Вы можете прикрепить неприкрепленный измененный объект, используя эту перегрузку:

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

Обратите внимание, что для того, чтобы это работало, в вашей таблице необходим столбец "Version" типа "timestamp"

2 голосов
/ 20 мая 2010

Существует обсуждение по этой теме здесь, на MSDN s рекомендуем использовать поле IsVersion и метод Attach

1 голос
/ 21 октября 2014

Это функция в моем классе репозитория, которую я использую для обновления сущностей

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 - ваш класс БД, и в зависимости от ваших настроек вы можете просто захотеть сделать

_dataContext.Attach(entity);
0 голосов
/ 15 октября 2015

Используйте этот метод расширения для обновления всех свойств, которые являются атрибутами столбца:

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

Я имею в виду, сначала вы восстанавливаете оригинал из базы данных, используете метод для сопоставления всех атрибутов столбцов от нового элемента к оригиналу и, наконец, делаете отправку. Надеюсь, это поможет.

...