Как обновить сущность в 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()? все, что я пишу, встречает различные исключения. (обратите внимание, что загруженные данные отслеживаются, подключены или что-то в этом роде)
3 ответа
Проблема в том, что ваши сущности Person все еще привязаны к контексту, созданному в GetPersons. Если вы хотите работать с присоединенными сущностями, вы должны использовать один и тот же экземпляр контекста в операциях выбора и обновления. У вас есть два варианта решения вашей проблемы.
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();
}
}
}
Взятый из Набора информации о сотрудниках, вы можете рассмотреть фрагмент кода, как показано ниже:
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();
}
Не работает, если у вас есть свойство объекта, являющегося 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