Как обновить объект в Entity Framework 4.NET

мой код выглядит примерно так:

public class Program
{
 [STAThread]
 static void main()
 {
  DataAccessClass dal = new DataAccessClass();
  List<Person> list = dal.GetPersons();
  Person p = list[0];
  p.LastName = "Changed!";
  dal.Update(p);
 }
}

public class DataAccessClass
{
 public static List<Person> GetPersons()
 {
  MyDBEntities context = new MyDBEntities();
  return context.Persons.ToList();
 }

 public void Update(Person p)
 {
  // what sould be written here?
 }
}

теперь, пожалуйста, скажите мне, что мне следует писать в методе Update()? все, что я пишу, встречает различные исключения. (обратите внимание, что загруженные данные отслеживаются, связаны или что-то в этом роде)

Ответ 1

Проблема заключается в том, что ваши объекты Person все еще привязаны к контексту, созданному в GetPersons. Если вы хотите работать с прикрепленными объектами, вы должны использовать один и тот же экземпляр контекста в операциях select и update. У вас есть два варианта решения вашей проблемы.

1) Правильно обработанные прикрепленные объекты

public class Program 
{ 
  [STAThread] 
  static void main() 
  { 
    using (DataAccessClass dal = new DataAccessClass())
    {
      List<Person> list = dal.GetPersons(); 
      Person p = list[0]; 
      p.LastName = "Changed!"; 
      dal.Save();
    } 
  } 
} 

public class DataAccessClass : IDisposable
{ 
  private MyDBEntities _context = new MyDBEntities(); 

  public List<Person> GetPersons() 
  { 
    return _context.Persons.ToList(); 
  } 

  public void Save() 
  { 
    // Context tracks changes on your entities. You don't have to do anything. Simply call
    // SaveChanges and all changes in all loaded entities will be done in DB.
    _context.SaveChanges();
  } 

  public void Dispose()
  {
    if (_context != null)
    {
      _context.Dispose();
      _context = null;
    }
  }
}

2) Не используйте прикрепленные объекты

public class Program 
{ 
  [STAThread] 
  static void main() 
  { 
    DataAccessClass dal = new DataAccessClass())
    List<Person> list = DataAccessClass.GetPersons(); 
    Person p = list[0]; 
    p.LastName = "Changed!"; 
    dal.Update(p);
  } 
} 

public class DataAccessClass
{ 
  public static List<Person> GetPersons() 
  {
    // Closing context will detach entities
    using (MyDBEntities context = new MyDBEntities())
    { 
      return context.Persons.ToList(); 
    }
  } 

  public void Update(Person p) 
  {  
    using (MyDBEntities context = new MyDBEntities())
    {
      context.Persons.Attach(p);
      // Detached entities don't track changes so after attaching you have to say
      // what changes have been done
      context.ObjectStateManager.ChangeObjectState(p, System.Data.EntityState.Modified);
      context.SaveChanges();
    }
  } 
}

Ответ 2

Взятый из "Стартовый комплект информации о сотрудниках" , вы можете рассмотреть фрагмент кода, как показано ниже:

public void UpdateEmployee(Employee updatedEmployee)
        {
            //attaching and making ready for parsistance
            if (updatedEmployee.EntityState == EntityState.Detached)
                _DatabaseContext.Employees.Attach(updatedEmployee);
            _DatabaseContext.ObjectStateManager.ChangeObjectState(updatedEmployee, System.Data.EntityState.Modified);
            _DatabaseContext.SaveChanges();
        }

Ответ 3

не работает, когда у вас есть свойство для объекта, который является ConcurrencyToken. По крайней мере для меня. Потому что вы получаете исключение OptimisticConcurrencyException.

Что я делаю (и я думаю, что это не оптимальное решение),

факты: - Я использую новый контекст из-за n-уровня. Таким образом, предыдущий/оригинальный объект со своими значениями неизвестен. Либо вы поставляет контекст оригинальным и старым (bah), либо как оригинал загрузки сначала перед обновлением:

T originalItem = sessionManager.Set().Single(x => x.ID == changedEntity.ID);

        if(changedEntity.lastChangedDate != originalItem.lastChangedDate)
            throw new OptimisticConcurrencyException(String.Format("Trying to update entity with lastChangedDate {0} using lastChangedDate {1}!", originalItem.lastChangedDate, changedEntity.lastChangedDate));

        ObjectStateEntry state = sessionManager.ObjectStateManager.GetObjectStateEntry(originalItem);
        state.ApplyCurrentValues(changedEntity);
        state.ChangeState(System.Data.EntityState.Modified);
        sessionManager.SaveChanges();

код >

Если вы знаете что-то лучше, пожалуйста, дайте мне знать.

Atam