Использовался подход Database First.
Имеется часть кода:
using (DBContext db = new DBContext())
{
currentAct = new Act()
{
ActNumber = actNumber,
EntryDateTime = DateTime.Now,
Employee = currentEmployee
};
db.Acts.Add(currentAct); // здесь ловлю исключение!
db.SaveChanges();
}
По каким вообще причинам может вылетать это исключение??
Проблема в том, что ваш currentEmployee
- не простой объект, а объект имеющий ссылку на контекст (точнее, на его Change Tracker, но это почти одно и то же). Отсюда и проблема: такой объект не может одновременно находиться в двух разных контекстах. Отдельно отмечу, что два разных контекста - это два разных объекта, а не два разных класса. Также отмечу, что проблема может быть не только в currentEmployee
, но и в любом объекте на который currentEmployee
ссылается.
Способов исправления этой проблемы - целая куча.
Прежде всего, сущности открепляются от контекста при разрушении этого самого контекста:
using (var db = new DBContext())
{
currentEmployee = db.Employees.Where(...).Single();
}
// Здесь currentEmployee уже можно использовать в другом контексте
Это - основной паттерн использования контекстов, и по возможности именно его следует использовать.
Если же по какой-то причине вы не можете разрушить контекст перед использованием currentEmployee
- вы можете попытаться не создавать новый контекст, а использовать старый:
using (var db = new DBContext())
{
currentEmployee = db.Employees.Where(...).Single();
var act = new Act { ... };
db.Acts.Add(act);
db.SaveChanges();
}
Если этот вариант также невозможен - то вы можете открепить currentEmployee
от контекста перед тем как его куда-то сохранять:
currentEmployee = db.Employees.Where(...).Single();
db.Entry(currentEmployee).State = EntityState.Detached;
С той же целью можно использовать метод AsNoTracking
:
currentEmployee = db.Employees.AsNoTracking().Where(...).Single();
Далее, можно выключить создание прокси-классов, это лишит currentEmployee
ссылки на контекст, позволив добавлять его к неограниченному числу контекстов:
using (var db = new DBContext())
{
db.Configuration.ProxyCreationEnabled = false;
currentEmployee = db.Employees.Where(...).Single();
}
Наконец, можно запретить EF создавать прокси для конкретного класса сущности, если объявить этот класс как sealed
:
public sealed class Employee
{
// ...
}
PS Использовав любое из приведенных решений (кроме второго), вы столкнетесь с ещё одной проблемой: EF не будет знать, что currentEmployee
уже лежит в базе данных, и попытается добавить эту сущность в базу ещё раз.
Эта проблема решается через метод Attach
:
using (DBContext db = new DBContext())
{
db.Employees.Attach(currentEmployee);
var currentAct = new Act
{
Employee = currentEmployee
// ...
};
db.Acts.Add(currentAct);
db.SaveChanges();
}
Альтернативная форма - через модификацию Entry State:
db.Entry(currentEmployee).State = EntityState.Unchanged;
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Подскажите, пожалуйста, я вывожу статьи и комментарии к ним в цикле PHP foreach